/*
* Hibernate OGM, Domain model persistence for NoSQL datastores
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.ogm.utils;
import static org.junit.Assert.fail;
import java.util.Deque;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicInteger;
import org.hibernate.search.util.logging.impl.Log;
import org.hibernate.search.util.logging.impl.LoggerFactory;
import org.jboss.byteman.rule.Rule;
import org.jboss.byteman.rule.helper.Helper;
/**
* @author Sanne Grinovero (C) 2011 Red Hat Inc.
* @author Hardy Ferentschik
*/
public class BytemanHelper extends Helper {
private static final Log log = LoggerFactory.make();
private static final String DEFAULT_COUNTER = "__DEFAULT_COUNTER_";
private static final Map<String, AtomicInteger> counters = new ConcurrentHashMap<>();
private static final Deque<String> concurrentStack = new ConcurrentLinkedDeque<>();
protected BytemanHelper(Rule rule) {
super( rule );
}
public void sleepASecond() {
try {
log.info( "Byteman rule triggered: sleeping a second" );
Thread.sleep( 1000 );
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error( "unexpected interruption", e );
}
}
public void assertBooleanValue(boolean actual, boolean expected) {
if ( actual != expected ) {
fail( "Unexpected boolean value" );
}
}
public void countInvocation() {
countInvocation( DEFAULT_COUNTER );
}
public void countInvocation(String counter) {
log.debug( "Increment call count for " + counter );
if ( !counters.containsKey( counter ) ) {
counters.put( counter, new AtomicInteger() );
}
counters.get( counter ).incrementAndGet();
}
public static int getAndResetInvocationCount() {
return getAndResetInvocationCount( DEFAULT_COUNTER );
}
public static int getAndResetInvocationCount(String counter) {
if ( !counters.containsKey( counter ) ) {
return 0;
}
return counters.get( counter ).getAndSet( 0 );
}
public static void resetCounters() {
counters.clear();
}
/**
* Adds a label to a concurrent queue.
* Useful to "tag" events to verify they are issued in a specific order,
* even though they are generated by different threads.
* @param message some label to be recorded
*/
public void pushEvent(String message) {
concurrentStack.add( message );
}
/**
* Gets the first event label from the concurrent queue,
* and removes it.
* The next invocation will return the next one from the queue.
* @return the first
*/
public static String consumeNextRecordedEvent() {
return concurrentStack.removeFirst();
}
public static boolean isEventStackEmpty() {
return concurrentStack.isEmpty();
}
/**
* Removes all state from the concurrent queue
* used to track events.
*/
static void resetEventStack() {
concurrentStack.clear();
}
}