Created
November 22, 2011 10:48
-
-
Save mmichaelis/1385405 to your computer and use it in GitHub Desktop.
BDD Design Pattern: Reference Tracker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import java.util.Collection; | |
import java.util.HashMap; | |
import java.util.Map; | |
/** | |
* <p> | |
* Tracks references between BDD steps. Typically you need some global variables or something alike to remember | |
* states between steps you perform. Extending classes will support you in doing so as you can | |
* {@link #track(Object, String, Object) track} objects in one step and {@link #get(Object, String, Class) get} | |
* them in the next step. | |
* </p> | |
* <p> | |
* Mind that your project should decide one common tracker to use as otherwise you might have problems | |
* asking the correct tracker for the object you want to retrieve. | |
* </p> | |
* | |
* @param <K> the type of the key used for tracking | |
* @param <V> type of the tracked values | |
*/ | |
public abstract class AbstractReferenceTracker<K, V> implements ReferenceTracker<K,V> { | |
/** | |
* My logger. | |
*/ | |
private static final Logger LOG = LoggerFactory.getLogger(AbstractReferenceTracker.class); | |
/** | |
* Initial size of the name-value map (the inner map). | |
*/ | |
private static final int INITIAL_NAME_VALUE_MAP_CAPACITY = 4; | |
/** | |
* Map which contains references where the outer map maps keys (most likely types) to name-value pairs in | |
* the inner map. | |
*/ | |
private final Map<K, Map<String, V>> references = new HashMap<K, Map<String, V>>(16); | |
/** | |
* {@inheritDoc} | |
*/ | |
@Override | |
public void track(final K type, final String name, final V obj) { | |
final Map<String, V> refToObject; | |
if (!references.containsKey(type)) { | |
refToObject = new HashMap<String, V>(INITIAL_NAME_VALUE_MAP_CAPACITY); | |
references.put(type, refToObject); | |
} else { | |
refToObject = references.get(type); | |
} | |
refToObject.put(name, obj); | |
} | |
/** | |
* {@inheritDoc} | |
*/ | |
@Override | |
public <T> T get(final K type, final String name, final Class<T> targetType) { | |
if (references.containsKey(type)) { | |
final V o = references.get(type).get(name); | |
return targetType.cast(o); | |
} | |
return null; | |
} | |
/** | |
* {@inheritDoc} | |
*/ | |
@Override | |
public final void cleanup() { | |
if (LOG.isDebugEnabled()) { | |
final Collection<Map<String, V>> values = references.values(); | |
int sum = 0; | |
for (final Map<String, V> value : values) { | |
sum += value.size(); | |
} | |
LOG.debug("Clearing {} tracked references.", sum); | |
} | |
references.clear(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* <p> | |
* Tracks references between BDD steps. Typically you need some global variables or something alike to remember | |
* states between steps you perform. Extending classes will support you in doing so as you can | |
* {@link #track(Object, String, Object) track} objects in one step and {@link #get(Object, String, Class) get} | |
* them in the next step. | |
* </p> | |
* <p> | |
* Mind that your project should decide one common tracker to use as otherwise you might have problems | |
* asking the correct tracker for the object you want to retrieve. | |
* </p> | |
* | |
* @param <K> the type of the key used for tracking | |
* @param <V> type of the tracked values | |
*/ | |
public interface ReferenceTracker<K, V> { | |
/** | |
* Tracks an object of a given type and name. If you track an object with the same parameters again it will | |
* overwrite the existing tracked object without further notice. | |
* @param type type of the object to track. Think of it like a namespace. | |
* @param name the name to use for the reference | |
* @param obj the object to track | |
*/ | |
void track(K type, String name, V obj); | |
/** | |
* Retrieve a tracked object and cast it to the given type. | |
* @param type the type/namespace of the object to retrieve | |
* @param name the reference name | |
* @param targetType the class of the object to retrieve | |
* @param <T> type of the tracked object | |
* @return <code>null</code>, if there is no such tracked element, otherwise the tracked element | |
*/ | |
<T> T get(K type, String name, Class<T> targetType); | |
/** | |
* Cleanup tracked references. Should be called either on <code>tearDown</code> of JUnit tests or after each scenario | |
* for example with the <code>@AfterScenario</code>-annotation. | |
*/ | |
void cleanup(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Inject | |
private TypedReferenceTracker tracker; | |
... | |
Content document = ... | |
tracker.track(Content.class, "A", document); | |
... | |
Content content = tracker.get(Content.class, "A"); | |
content.doSomething(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.annotation.ManagedBean; | |
/** | |
* <p> | |
* Tracks objects grouped by their classes. | |
* </p> | |
* <p><strong>Example:</strong></p> | |
* <pre> | |
* @Inject | |
* private TypedReferenceTracker tracker; | |
* ... | |
* Content document = ... | |
* tracker.track(Content.class, "A", document); | |
* ... | |
* Content content = tracker.get(Content.class, "A"); | |
* content.doSomething(); | |
* </pre> | |
*/ | |
@SuppressWarnings("JavaDoc") | |
@ManagedBean | |
public class TypedReferenceTracker extends AbstractReferenceTracker<Class<?>, Object> { | |
/** | |
* Retrieve tracked object identified by its class and its reference name. | |
* @param type the type of the object to retrieve | |
* @param name the name of the reference | |
* @param <T> type of the object | |
* @return null if there is no such tracked object, otherwise the tracked object | |
*/ | |
public <T> T get(final Class<T> type, final String name) { | |
return get(type, name, type); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment