blob: dc1211913ed25266db19690670cc3a5dfc4b40b5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.tracecompass.internal.tmf.analysis.xml.core.fsm.model;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.Activator;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.fsm.model.runtime.DataDrivenScenarioInfo;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.fsm.model.values.DataDrivenValue;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.fsm.module.IAnalysisDataContainer;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
import org.eclipse.tracecompass.tmf.analysis.xml.core.module.TmfXmlStrings;
import org.eclipse.tracecompass.tmf.analysis.xml.core.module.TmfXmlUtils;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider.FutureEventType;
/**
* An action that assigns a value to a path in a state system
*
* @author Geneviève Bastien
* @author Florian Wininger
*/
public class DataDrivenActionStateChange implements DataDrivenAction {
/**
* An enumeration of possible actions on stack
*/
public enum StackAction {
/** No action */
NONE,
/** Push a value to the stack */
PUSH,
/** Peek the top of a stack */
PEEK,
/** Pop a value from a stack */
POP,
/** Pops all the values from the stack */
POP_ALL;
/**
* Get the type stack value corresponding to a string
*
* @param input
* The string to match to a value
* @return The ValueTypeStack value
*/
public static StackAction getTypeFromString(String input) {
switch (input) {
case TmfXmlStrings.STACK_PUSH:
return PUSH;
case TmfXmlStrings.STACK_POP:
return POP;
case TmfXmlStrings.STACK_POPALL:
return POP_ALL;
case TmfXmlStrings.STACK_PEEK:
return PEEK;
default:
return NONE;
}
}
}
private final DataDrivenValue fRightOperand;
private final DataDrivenStateSystemPath fLeftOperand;
// private final List<DataDrivenValue> fLeftOperand;
private final boolean fUpdate;
private final boolean fIncrement;
private final StackAction fStackAction;
private final @Nullable DataDrivenValue fFutureTime;
/**
* Constructor
*
* @param leftOperand
* The left operands (path in the state system)
* @param rightOperand
* The right operand, ie the value to assign
* @param increment
* If <code>true</code>, the value of the right operand will be added
* to the preceding value
* @param update
* If <code>true</code>, the resulting value will be updated and will
* not create a state change, otherwise, the value will be modified
* and a new state will start at the time of the event.
* @param stackAction
* The action to perform on a stack
* @param futureTime
* The state value for the future time. If the state change happens
* at the time of the event, this value should be null
*/
public DataDrivenActionStateChange(DataDrivenStateSystemPath leftOperand, DataDrivenValue rightOperand, boolean increment, boolean update, StackAction stackAction, @Nullable DataDrivenValue futureTime) {
fRightOperand = rightOperand;
fLeftOperand = leftOperand;
fUpdate = update;
fIncrement = increment;
fStackAction = stackAction;
fFutureTime = futureTime;
}
@Override
public void eventHandle(ITmfEvent event, DataDrivenScenarioInfo scenarioInfo, IAnalysisDataContainer container) {
int quark = ITmfStateSystem.ROOT_ATTRIBUTE;
ITmfStateSystem stateSystem = container.getStateSystem();
if (!(stateSystem instanceof ITmfStateSystemBuilder)) {
throw new IllegalStateException("With state changes, the state system should be in building mode"); //$NON-NLS-1$
}
ITmfStateSystemBuilder ssb = (ITmfStateSystemBuilder) stateSystem;
// Get the quark that will be changed
quark = fLeftOperand.getQuark(event, quark, scenarioInfo, container);
if (quark < 0) {
return;
}
// Get the value
Object assignVal = fRightOperand.getValue(event, ITmfStateSystem.ROOT_ATTRIBUTE, scenarioInfo, container);
long timestamp = event.getTimestamp().toNanos();
// Should this state change be done at a future time?
long scTime = timestamp;
if (fFutureTime != null) {
Object futureTimeObj = fFutureTime.getValue(event, ITmfStateSystem.ROOT_ATTRIBUTE, scenarioInfo, container);
if (futureTimeObj instanceof Number) {
scTime = ((Number) futureTimeObj).longValue();
} else {
try {
// Try parsing the value
scTime = Long.parseLong(String.valueOf(futureTimeObj));
} catch (NumberFormatException e) {
try {
// Maybe it's a double, XML scripts return double for
// instance
scTime = Double.valueOf(Double.parseDouble(String.valueOf(futureTimeObj))).longValue();
} catch (NumberFormatException e1) {
// Cannot convert to number, ignore
}
}
}
}
// Perform the stack action if applicable and return
switch (fStackAction) {
case POP:
if (scTime > timestamp) {
container.addFutureState(scTime, assignVal, quark, FutureEventType.POP);
} else {
ssb.popAttribute(timestamp, quark);
}
return;
case PUSH:
if (scTime > timestamp) {
container.addFutureState(scTime, assignVal, quark, FutureEventType.PUSH);
} else {
ssb.pushAttribute(timestamp, assignVal, quark);
}
return;
case POP_ALL:
// The stack state will contain the number of elements on the stack
Object stackDepth = ssb.queryOngoing(quark);
if (stackDepth instanceof Integer) {
int nbElements = ((Integer) stackDepth).intValue();
for (int i = 0; i < nbElements; i++) {
if (scTime > timestamp) {
container.addFutureState(scTime, assignVal, quark, FutureEventType.POP);
} else {
ssb.popAttribute(timestamp, quark);
}
}
}
return;
case NONE:
case PEEK:
default:
break;
}
// Increment if necessary
if (fIncrement && assignVal != null) {
assignVal = incrementByType(quark, ssb, assignVal);
}
// If update is requested, do update and return
if (fUpdate) {
ssb.updateOngoingState(TmfXmlUtils.newTmfStateValueFromObject(assignVal), quark);
} else if (scTime == timestamp) {
ssb.modifyAttribute(timestamp, assignVal, quark);
} else if (scTime > timestamp) {
container.addFutureState(scTime, assignVal, quark, FutureEventType.MODIFICATION);
} else {
Activator.logWarning("No state change occurred for event " + event + " and state change " + this + ". The time of the change is invalid: " + scTime); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
}
}
private static @Nullable Object incrementByType(int quark, ITmfStateSystem ss, Object stateValue) {
if (stateValue instanceof Long) {
Long incrementLong = (Long) stateValue;
Object currentState = ss.queryOngoing(quark);
Long currentValue = (currentState == null ? 0 : (Long) currentState);
return incrementLong + currentValue;
}
if (stateValue instanceof Integer) {
Integer incrementLong = (Integer) stateValue;
Object currentState = ss.queryOngoing(quark);
Integer currentValue = (currentState == null ? 0 : (Integer) currentState);
return incrementLong + currentValue;
}
return stateValue;
}
}