blob: c46cd4a389dec9ae6876c0e2696226c197109c8b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2016 É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.tmf.tests.stubs.analysis;
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
import org.eclipse.tracecompass.tmf.core.statesystem.AbstractTmfStateProvider;
import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
/**
* Stub test provider for test state system analysis module
*
* @author Geneviève Bastien
*/
public class TestStateSystemProvider extends AbstractTmfStateProvider {
/**
* This interface allows unit tests to provide only the event handling part
* of the state provider, without having to extend the analysis and the
* classes
*/
@FunctionalInterface
public static interface TestStateProviderHandler {
/**
* Handles the event
*
* @param ss
* The state system builder
* @param provider
* The state provider
* @param event
* The event to handler
* @return <code>true</code> if everything went fine, or
* <code>false</code> to cancel
*/
boolean eventHandle(@NonNull ITmfStateSystemBuilder ss, AbstractTmfStateProvider provider, ITmfEvent event);
}
private static final int VERSION = 1;
private static final String fString = "[]";
private static int fCount = 0;
private static final @NonNull TestStateProviderHandler DEFAULT_HANDLER = (ss, provider, event) -> {
/* Just need something to fill the state system */
if (fString.equals(event.getContent().getValue())) {
try {
int quarkId = ss.getQuarkAbsoluteAndAdd("String");
int quark = ss.getQuarkRelativeAndAdd(quarkId, fString);
ss.modifyAttribute(event.getTimestamp().getValue(), fCount++, quark);
} catch (TimeRangeException | StateValueTypeException e) {
}
}
return true;
};
private static @NonNull TestStateProviderHandler sfHandler = DEFAULT_HANDLER;
/**
* Set the event handler for the state provider
*
* @param handler
* The class containing the event handler for this state provider
*/
public static void setEventHandler(TestStateProviderHandler handler) {
if (handler == null) {
sfHandler = DEFAULT_HANDLER;
return;
}
sfHandler = handler;
}
private final Lock fLock = new ReentrantLock();
private @Nullable Condition fNextEventSignal = null;
/**
* Constructor
*
* @param trace
* The trace this state provider is for
*/
public TestStateSystemProvider(@NonNull ITmfTrace trace) {
super(trace, "Stub State System");
}
/**
* Constructor
*
* @param trace
* The trace this state provider is for
* @param size
* The size of the queue, a.k.a the number of chunks that fit
* into the buffered queue.
* @param chunk
* the size of a events that fit inside a chunk of the queue
*/
public TestStateSystemProvider(@NonNull ITmfTrace trace, int size, int chunk) {
super(trace, "Stub State System", size, chunk);
}
@Override
public int getVersion() {
return VERSION;
}
@Override
public ITmfStateProvider getNewInstance() {
return new TestStateSystemProvider(this.getTrace());
}
@Override
protected void eventHandle(ITmfEvent event) {
ITmfStateSystemBuilder ss = checkNotNull(getStateSystemBuilder());
sfHandler.eventHandle(ss, this, event);
}
@Override
public void processEvent(@NonNull ITmfEvent event) {
fLock.lock();
try {
Condition cond = fNextEventSignal;
if (cond != null) {
cond.await();
}
} catch (InterruptedException e) {
} finally {
super.processEvent(event);
fLock.unlock();
}
}
/**
* Set the processing of event to be one event at a time instead of the
* default behavior. It will block until the next call to
* {@link #signalNextEvent()} method call.
*
* @param throttleEvent
* Whether to wait for a signal to process the next event
*/
public void setThrottling(boolean throttleEvent) {
fLock.lock();
try {
if (throttleEvent) {
Condition cond = fNextEventSignal;
// If called for the first time, create a condition
if (cond == null) {
cond = fLock.newCondition();
fNextEventSignal = cond;
}
} else {
Condition cond = fNextEventSignal;
if (cond != null) {
fNextEventSignal = null;
cond.signalAll();
}
}
} finally {
fLock.unlock();
}
}
/**
* Signal for the next event to be processed. Calling this method makes
* sense only if {@link #setThrottling(boolean)} has been set to true
*/
public void signalNextEvent() {
fLock.lock();
try {
Condition cond = fNextEventSignal;
if (cond != null) {
cond.signalAll();
}
} finally {
fLock.unlock();
}
}
}