trace/tracebuilder/com.nokia.tracebuilder/src/com/nokia/tracebuilder/engine/rules/RulesEngine.java
changeset 10 ed1c9f64298a
equal deleted inserted replaced
9:14dc2103a631 10:ed1c9f64298a
       
     1 /*
       
     2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 * Implementation of TraceObjectRuleFactory interface
       
    17 *
       
    18 */
       
    19 package com.nokia.tracebuilder.engine.rules;
       
    20 
       
    21 import java.util.Iterator;
       
    22 
       
    23 import com.nokia.tracebuilder.engine.TraceBuilderConfiguration;
       
    24 import com.nokia.tracebuilder.engine.TraceBuilderConfigurationListener;
       
    25 import com.nokia.tracebuilder.engine.TraceBuilderGlobals;
       
    26 import com.nokia.tracebuilder.engine.TraceObjectPropertyDialogConfiguration;
       
    27 import com.nokia.tracebuilder.engine.rules.osttrace.OstTraceFormatRule;
       
    28 import com.nokia.tracebuilder.engine.rules.printf.PrintfExtensionParserRule;
       
    29 import com.nokia.tracebuilder.engine.rules.printf.PrintfTraceParserRule;
       
    30 import com.nokia.tracebuilder.engine.source.SourceParserRule;
       
    31 import com.nokia.tracebuilder.engine.source.TraceParameterFormattingRule;
       
    32 import com.nokia.tracebuilder.model.Trace;
       
    33 import com.nokia.tracebuilder.model.TraceModel;
       
    34 import com.nokia.tracebuilder.model.TraceModelExtension;
       
    35 import com.nokia.tracebuilder.model.TraceModelListener;
       
    36 import com.nokia.tracebuilder.model.TraceModelPersistentExtension;
       
    37 import com.nokia.tracebuilder.model.TraceModelResetListener;
       
    38 import com.nokia.tracebuilder.model.TraceObject;
       
    39 import com.nokia.tracebuilder.model.TraceObjectRuleFactory;
       
    40 import com.nokia.tracebuilder.model.TraceParameter;
       
    41 import com.nokia.tracebuilder.project.TraceProjectAPI;
       
    42 import com.nokia.tracebuilder.rules.FillerParameterRule;
       
    43 import com.nokia.tracebuilder.source.SourceUtils;
       
    44 
       
    45 /**
       
    46  * Provides rules for trace objects.
       
    47  * 
       
    48  */
       
    49 public class RulesEngine implements TraceObjectRuleFactory {
       
    50 
       
    51 	/**
       
    52 	 * Number of parameters in a simple trace
       
    53 	 */
       
    54 	private static final int SIMPLE_TRACE_MAX_PARAMETER_COUNT = 1;
       
    55 
       
    56 	/**
       
    57 	 * Trace model listener updates the fillers and complex type flagging when
       
    58 	 * traces and parameters are modified
       
    59 	 */
       
    60 	private TraceModelListener modelListener;
       
    61 
       
    62 	/**
       
    63 	 * Trace model reset listener uses modelValid to update the complex header
       
    64 	 * rules
       
    65 	 */
       
    66 	private TraceModelResetListener resetListener;
       
    67 
       
    68 	/**
       
    69 	 * Manager for plug-in API's
       
    70 	 */
       
    71 	private RulesEnginePluginManager pluginManager;
       
    72 
       
    73 	/**
       
    74 	 * Configuration listener for source format changes
       
    75 	 */
       
    76 	private TraceBuilderConfigurationListener configurationListener = new RulesEngineConfigurationListener(
       
    77 			this);
       
    78 
       
    79 	/**
       
    80 	 * Property dialog configuration
       
    81 	 */
       
    82 	private TraceObjectPropertyDialogConfiguration propertyDialogConfiguration = new PropertyDialogConfiguration();
       
    83 
       
    84 	/**
       
    85 	 * Trace model
       
    86 	 */
       
    87 	private TraceModel model;
       
    88 
       
    89 	/**
       
    90 	 * Constructor
       
    91 	 */
       
    92 	public RulesEngine() {
       
    93 		TraceBuilderGlobals.getConfiguration().addConfigurationListener(
       
    94 				configurationListener);
       
    95 	}
       
    96 
       
    97 	/**
       
    98 	 * Gets the property dialog configuration
       
    99 	 * 
       
   100 	 * @return the configuration
       
   101 	 */
       
   102 	public TraceObjectPropertyDialogConfiguration getPropertyDialogConfiguration() {
       
   103 		return propertyDialogConfiguration;
       
   104 	}
       
   105 
       
   106 	/*
       
   107 	 * (non-Javadoc)
       
   108 	 * 
       
   109 	 * @see com.nokia.tracebuilder.model.TraceObjectRuleFactory#
       
   110 	 *      createExtension(com.nokia.tracebuilder.model.TraceObject,
       
   111 	 *      java.lang.String)
       
   112 	 */
       
   113 	public TraceModelPersistentExtension createExtension(TraceObject target,
       
   114 			String name) {
       
   115 		TraceModelPersistentExtension retval = null;
       
   116 		ClassNameWrapper[] table = RulesEngineConstants.PERSISTENT_EXTENSIONS;
       
   117 		for (int i = 0; i < table.length && retval == null; i++) {
       
   118 			if (name.equals(table[i].name)) {
       
   119 				retval = createPersistentExtensionAt(target, i);
       
   120 			}
       
   121 		}
       
   122 		return retval;
       
   123 	}
       
   124 
       
   125 	/**
       
   126 	 * Creates a persistent extension
       
   127 	 * 
       
   128 	 * @param target
       
   129 	 *            the target object
       
   130 	 * @param i
       
   131 	 *            index to the persistent extensions array
       
   132 	 * @return the extension
       
   133 	 */
       
   134 	private TraceModelPersistentExtension createPersistentExtensionAt(
       
   135 			TraceObject target, int i) {
       
   136 		ClassNameWrapper wrapper = RulesEngineConstants.PERSISTENT_EXTENSIONS[i];
       
   137 		TraceModelPersistentExtension retval = null;
       
   138 		TraceModelPersistentExtension o = target.getExtension(wrapper.clasz);
       
   139 		if (o == null) {
       
   140 			try {
       
   141 				retval = wrapper.clasz.newInstance();
       
   142 			} catch (Exception e) {
       
   143 				if (TraceBuilderConfiguration.ASSERTIONS_ENABLED) {
       
   144 					TraceBuilderGlobals.getEvents().postAssertionFailed(
       
   145 							"Invalid extension - " + wrapper.name, null); //$NON-NLS-1$
       
   146 				}
       
   147 			}
       
   148 		}
       
   149 		return retval;
       
   150 	}
       
   151 
       
   152 	/*
       
   153 	 * (non-Javadoc)
       
   154 	 * 
       
   155 	 * @see com.nokia.tracebuilder.model.TraceObjectRuleFactory#
       
   156 	 *      preProcessNewRules(com.nokia.tracebuilder.model.TraceObject)
       
   157 	 */
       
   158 	public void preProcessNewRules(TraceObject object) {
       
   159 		if (object instanceof Trace) {
       
   160 			// Instrumenter rules are added to instrumented traces
       
   161 			if (TraceBuilderGlobals.getSourceContextManager().isInstrumenting()) {
       
   162 				object.addExtension(new InstrumentedTraceRuleImpl(
       
   163 						TraceBuilderGlobals.getSourceContextManager()
       
   164 								.getInstrumenterID()));
       
   165 			}
       
   166 		} else if (object instanceof TraceModel) {
       
   167 			// NOTE: This is only called once when builder is started
       
   168 			// There is no cleanup code
       
   169 			this.model = (TraceModel) object;
       
   170 			modelListener = new RulesEngineModelListener(this);
       
   171 			resetListener = new RulesEngineResetListener(this, model);
       
   172 			model.addModelListener(modelListener);
       
   173 			model.addResetListener(resetListener);
       
   174 			// Adds the plug-in trace parser / formatter manager to the model as
       
   175 			// extension. The plug-in manager delegates the formatters and
       
   176 			// parsers to this object when plug-in components register to
       
   177 			// TraceBuilder.
       
   178 			pluginManager = new RulesEnginePluginManager(this);
       
   179 			model.addExtension(pluginManager);
       
   180 			createTraceParsers();
       
   181 			createTraceAPIs();
       
   182 		}
       
   183 	}
       
   184 
       
   185 	/**
       
   186 	 * Creates the trace parsers and stores them to the model
       
   187 	 */
       
   188 	private void createTraceParsers() {
       
   189 		for (SourceParserRule element : RulesEngineConstants.TRACE_PARSERS) {
       
   190 			// Creates all source parsers specified in the constants
       
   191 			model.addExtension(element);
       
   192 		}
       
   193 	}
       
   194 
       
   195 	/**
       
   196 	 * Enables / disables the printf parsers
       
   197 	 * 
       
   198 	 * @param flag
       
   199 	 *            enable flag
       
   200 	 */
       
   201 	void enablePrintfParser(boolean flag) {
       
   202 		if (flag) {
       
   203 			for (String element : RulesEngineConstants.PRINTF_PARSERS) {
       
   204 				SourceParserRuleBase parser = new PrintfTraceParserRule(element);
       
   205 				model.addExtension(parser);
       
   206 			}
       
   207 		} else {
       
   208 			Iterator<SourceParserRuleBase> rules = model
       
   209 					.getExtensions(SourceParserRuleBase.class);
       
   210 			boolean found;
       
   211 			do {
       
   212 				found = false;
       
   213 				while (rules.hasNext() && !found) {
       
   214 					SourceParserRuleBase parser = rules.next();
       
   215 					for (int i = 0; i < RulesEngineConstants.PRINTF_PARSERS.length; i++) {
       
   216 						if (parser.getSearchTag().equals(
       
   217 								RulesEngineConstants.PRINTF_PARSERS[i])) {
       
   218 							model.removeExtension(parser);
       
   219 							found = true;
       
   220 							i = RulesEngineConstants.PRINTF_PARSERS.length;
       
   221 						}
       
   222 					}
       
   223 				}
       
   224 			} while (found);
       
   225 		}
       
   226 	}
       
   227 
       
   228 	/**
       
   229 	 * Sets the parser macro extension
       
   230 	 * 
       
   231 	 * @param macro
       
   232 	 *            the new parser macro
       
   233 	 */
       
   234 	void setPrintfMacroExtension(String macro) {
       
   235 		PrintfExtensionParserRule parser = model
       
   236 				.getExtension(PrintfExtensionParserRule.class);
       
   237 		boolean changed = true;
       
   238 		if (parser != null) {
       
   239 			String oldtag = parser.getSearchTag();
       
   240 			if (oldtag.equals(macro)) {
       
   241 				changed = false;
       
   242 			} else {
       
   243 				model.removeExtension(parser);
       
   244 			}
       
   245 		}
       
   246 		if (changed && macro != null && macro.length() > 0) {
       
   247 			parser = new PrintfExtensionParserRule(macro);
       
   248 			model.addExtension(parser);
       
   249 		}
       
   250 	}
       
   251 
       
   252 	/**
       
   253 	 * Creates the default trace API's and adds them to the plug-in manager
       
   254 	 */
       
   255 	private void createTraceAPIs() {
       
   256 		for (TraceProjectAPI api : RulesEngineConstants.TRACE_APIS) {
       
   257 			pluginManager.addAPI(api);
       
   258 		}
       
   259 	}
       
   260 
       
   261 	/**
       
   262 	 * Creates the trace formatter and stores it to the model
       
   263 	 */
       
   264 	void setDefaultTraceAPI() {
       
   265 		// If the formatter did not exist in the project file, it is added based
       
   266 		// on the configuration default
       
   267 		if (model.getExtension(TraceProjectAPI.class) == null) {
       
   268 			String api = TraceBuilderGlobals.getConfiguration().getText(
       
   269 					TraceBuilderConfiguration.FORMATTER_NAME);
       
   270 			traceAPIChanged(api);
       
   271 		}
       
   272 	}
       
   273 
       
   274 	/**
       
   275 	 * API change notification
       
   276 	 * 
       
   277 	 * @param apiName
       
   278 	 *            the name of new api
       
   279 	 */
       
   280 	void traceAPIChanged(String apiName) {
       
   281 		TraceProjectAPI api = model.getExtension(TraceProjectAPI.class);
       
   282 		boolean found = false;
       
   283 		if (api != null) {
       
   284 			if (api.getName().equals(apiName)) {
       
   285 				found = true;
       
   286 			} else {
       
   287 				model.removeExtension(api);
       
   288 			}
       
   289 		}
       
   290 		if (!found) {
       
   291 			changeTraceAPI(apiName);
       
   292 		}
       
   293 	}
       
   294 
       
   295 	/**
       
   296 	 * Creates a trace API
       
   297 	 * 
       
   298 	 * @param apiName
       
   299 	 *            the name of the API to be created
       
   300 	 */
       
   301 	void changeTraceAPI(String apiName) {
       
   302 		if (apiName == null || apiName.length() == 0) {
       
   303 			apiName = OstTraceFormatRule.STORAGE_NAME;
       
   304 		}
       
   305 		Iterator<TraceProjectAPI> apis = pluginManager.getAPIs();
       
   306 		boolean apifound = false;
       
   307 		while (apis.hasNext()) {
       
   308 			TraceProjectAPI api = apis.next();
       
   309 			if (api.getName().equals(apiName)) {
       
   310 				model.addExtension(api);
       
   311 				apifound = true;
       
   312 			}
       
   313 		}
       
   314 		if (!apifound) {
       
   315 			// If API from configuration was not found, the first one is used
       
   316 			apis = pluginManager.getAPIs();
       
   317 			if (apis.hasNext()) {
       
   318 				model.addExtension(apis.next());
       
   319 			}
       
   320 		}
       
   321 	}
       
   322 
       
   323 	/*
       
   324 	 * (non-Javadoc)
       
   325 	 * 
       
   326 	 * @see com.nokia.tracebuilder.model.TraceObjectRuleFactory#
       
   327 	 *      postProcessNewRules(com.nokia.tracebuilder.model.TraceObject)
       
   328 	 */
       
   329 	public void postProcessNewRules(TraceObject object) {
       
   330 	}
       
   331 
       
   332 	/**
       
   333 	 * Checks the count and types of parameters of given trace and flags it with
       
   334 	 * ComplexParameterRule if necessary
       
   335 	 * 
       
   336 	 * @param trace
       
   337 	 *            the trace
       
   338 	 */
       
   339 	void checkParameterTypes(Trace trace) {
       
   340 		// When converting traces from source, the converter takes care of
       
   341 		// flagging the traces as complex. The complex flag needs to be checked
       
   342 		// when trace are modified via UI
       
   343 		if (!TraceBuilderGlobals.getSourceContextManager().isConverting()) {
       
   344 			boolean complex = false;
       
   345 			int count = trace.getParameterCount();
       
   346 			Iterator<TraceParameter> itr = trace.getParameters();
       
   347 			while (itr.hasNext() && !complex) {
       
   348 				TraceParameter parameter = itr.next();
       
   349 				TraceParameterFormattingRule rule = parameter
       
   350 						.getExtension(TraceParameterFormattingRule.class);
       
   351 				boolean isShown = true;
       
   352 				if (rule != null && !rule.isShownInSource()) {
       
   353 					isShown = false;
       
   354 				}
       
   355 				if (isShown) {
       
   356 					complex = !SourceUtils.isSimpleType(parameter);
       
   357 				} else {
       
   358 					count--;
       
   359 				}
       
   360 			}
       
   361 			// Any trace with more than one parameter is a complex trace
       
   362 			if (!complex && count > SIMPLE_TRACE_MAX_PARAMETER_COUNT) {
       
   363 				complex = true;
       
   364 			}
       
   365 			ComplexHeaderRule rule = trace
       
   366 					.getExtension(ComplexHeaderRule.class);
       
   367 			if (complex && rule == null) {
       
   368 				trace.addExtension(new ComplexHeaderRuleImpl());
       
   369 			} else if (!complex && rule != null) {
       
   370 				trace.removeExtension(rule);
       
   371 			}
       
   372 		}
       
   373 	}
       
   374 
       
   375 	/**
       
   376 	 * Adds fillers to align trace parameters to 32-bit boundaries.
       
   377 	 * 
       
   378 	 * @param trace
       
   379 	 *            the trace to be updated
       
   380 	 */
       
   381 	void checkFillerParameters(Trace trace) {
       
   382 		// Flags the model so listeners don't perform intermediate updates
       
   383 		trace.getModel().startProcessing();
       
   384 		try {
       
   385 			// Removes all existing fillers
       
   386 			for (int i = 0; i < trace.getParameterCount(); i++) {
       
   387 				TraceParameter parameter = trace.getParameter(i);
       
   388 				if (parameter.getExtension(FillerParameterRule.class) != null) {
       
   389 					trace.removeParameterAt(i);
       
   390 					i--;
       
   391 				}
       
   392 			}
       
   393 			int bytesInBlock = 0;
       
   394 			int parameterIndex = 0;
       
   395 			for (; parameterIndex < trace.getParameterCount(); parameterIndex++) {
       
   396 				TraceParameter parameter = trace.getParameter(parameterIndex);
       
   397 				int paramSize = SourceUtils.mapParameterTypeToSize(parameter);
       
   398 				// Parameters are aligned to 32 bits. Parameter after
       
   399 				// end-of-string is aligned dynamically and thus no filler is
       
   400 				// created for it
       
   401 				if (paramSize == 0 || paramSize == 4 || paramSize == 8) { // CodForChk_Dis_Magic
       
   402 					if (bytesInBlock > 0) {
       
   403 						int fillerCount = 4 - bytesInBlock; // CodForChk_Dis_Magic
       
   404 						for (int i = 0; i < fillerCount; i++) {
       
   405 							createFillerParameter(trace, parameterIndex++);
       
   406 						}
       
   407 						bytesInBlock = 0;
       
   408 					}
       
   409 				} else if (paramSize == 2) { // CodForChk_Dis_Magic
       
   410 					if (bytesInBlock == 1 || bytesInBlock == 3) { // CodForChk_Dis_Magic
       
   411 						createFillerParameter(trace, parameterIndex++);
       
   412 						// If there was 1 existing byte and filler was added,
       
   413 						// the number of bytes in the block is now 4 including
       
   414 						// the 2-byte parameter. If there was 3 bytes, the
       
   415 						// filler brings it to 4 and the 16-bit parameter
       
   416 						// changes it to 2
       
   417 						bytesInBlock += 3; // CodForChk_Dis_Magic
       
   418 					} else {
       
   419 						bytesInBlock += 2; // CodForChk_Dis_Magic
       
   420 					}
       
   421 					if (bytesInBlock >= 4) { // CodForChk_Dis_Magic
       
   422 						bytesInBlock -= 4; // CodForChk_Dis_Magic
       
   423 					}
       
   424 				} else {
       
   425 					bytesInBlock++;
       
   426 					if (bytesInBlock == 4) { // CodForChk_Dis_Magic
       
   427 						bytesInBlock = 0;
       
   428 					}
       
   429 				}
       
   430 			}
       
   431 			// Adds fillers also the the end of the parameter list
       
   432 			if (bytesInBlock > 0) {
       
   433 				int fillerCount = 4 - bytesInBlock; // CodForChk_Dis_Magic
       
   434 				for (int i = 0; i < fillerCount; i++) {
       
   435 					createFillerParameter(trace, parameterIndex++);
       
   436 				}
       
   437 				bytesInBlock = 0;
       
   438 			}
       
   439 		} finally {
       
   440 			trace.getModel().processingComplete();
       
   441 		}
       
   442 	}
       
   443 
       
   444 	/**
       
   445 	 * Creates a filler parameter
       
   446 	 * 
       
   447 	 * @param trace
       
   448 	 *            the trace for the parameter
       
   449 	 * @param parameterIndex
       
   450 	 *            the index where the filler is inserted
       
   451 	 */
       
   452 	private void createFillerParameter(Trace trace, int parameterIndex) {
       
   453 		trace.getModel().getFactory().createTraceParameter(parameterIndex,
       
   454 				trace, trace.getParameterCount(),
       
   455 				"Filler", //$NON-NLS-1$
       
   456 				TraceParameter.HEX8,
       
   457 				new TraceModelExtension[] { new FillerParameterRuleImpl() });
       
   458 	}
       
   459 
       
   460 }