package org.magenta.core;
import java.util.Arrays;
import java.util.Collection;
import org.magenta.FixtureFactory;
import org.magenta.DataKey;
import org.magenta.DataSet;
import org.magenta.QualifiedDataSet;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
/**
* Helper class for restriction applications. By "restrictions", we mean
* replacing an existing dataset by a fixed one having only one or two elements.
* The purpose of doing this is to restrain the range of a certain type of data
* so every other dataset depending on it for their generation are forced to use
* a small sample. Let say we have a dataset of "City" containing dozens of
* cities. This dataset is used by a generation strategy to generate "Monument".
* Each "Monument" generated within one of the available cities. If we want to
* generate "Monument" for the city of Paris only, then we need to "restrict"
* the dataset of Cities to only one element being "Paris".
*
* Here is a sample of code:
*
* <pre>
* FixtureFactory tourismDomain = TourismDomain.createDomain();
* City paris = CityBuilder.build("Paris"); // custom logic to
* // create/build/generate a city
* Monument monument = tourismDomain.restrictTo(paris)
* .dataset(Monument.class)
* .any(); // existing
* // city
* // dataset
* // replaced
* // by
* // a
* // unique
* // element
* // dataset
*
* Assert.assertEquals(paris, monument.getCity());
*
* </pre>
*
* @author ngagnon
*
*/
public class RestrictionHelper {
private static final Object EMPTY = new Object();
/**
* Fixes corresponding dataset with the given <code>objects</code> into the
* <code>domain</code>.
*
* @param domain
* the domain
* @param objects
* an array of object
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void applyRestrictions(FixtureFactory<?> domain, Object... objects) {
Multimap<DataKey<?>, Object> multimap = ArrayListMultimap.create();
normalize(domain, Arrays.asList(objects), multimap);
for (DataKey key : multimap.keySet()) {
Collection<Object> objs = multimap.get(key);
if (objs.size() == 1 && objs.iterator()
.next() == EMPTY) {
domain.newDataSet(key)
.composedOf();
} else {
domain.newDataSet(key)
.composedOf(multimap.get(key));
}
}
}
@VisibleForTesting
static void normalize(FixtureFactory<?> domain, Iterable<?> objects, Multimap<DataKey<?>, Object> multimap) {
for (Object o : objects) {
if (o instanceof QualifiedDataSet) {
QualifiedDataSet<?> qDataSetItem = (QualifiedDataSet<?>) o;
if (!qDataSetItem.isEmpty()) {
multimap.putAll(qDataSetItem.getKey(), qDataSetItem.get());
} else {
if (multimap.get(qDataSetItem.getKey())
.isEmpty()) {
multimap.put(qDataSetItem.getKey(), EMPTY);
}
;
}
} else if (o instanceof DataSet) {
DataSet<?> dataSetItem = (DataSet<?>) o;
DataKey<?> key = DataKey.makeDefault(dataSetItem.getType());
if (!dataSetItem.isEmpty()) {
multimap.putAll(key, dataSetItem.get());
} else {
if (!multimap.containsKey(key)) {
multimap.put(key, EMPTY);
}
}
} else if (o instanceof Iterable) {
Iterable<?> iterableItem = (Iterable<?>) o;
normalize(domain, iterableItem, multimap);
} else if (o.getClass()
.isArray()) {
Object[] arrayItem = (Object[]) o;
normalize(domain, Arrays.asList(arrayItem), multimap);
} else {
DataKey<?> key = findKeyForClass(domain, o.getClass());
if (key == null) {
throw new IllegalArgumentException("Cannot restrict with " + o.getClass() + ", this dataset does not exist in this DataSetManager.");
}
multimap.put(key, o);
}
}
}
@VisibleForTesting
static DataKey<?> findKeyForClass(FixtureFactory<?> domain, Class<? extends Object> clazz) {
DataKey<?> key = DataKey.makeDefault(clazz);
if (domain.datasetKeys()
.contains(key)) {
return key;
}
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> i : interfaces) {
key = findKeyForClass(domain, i);
if (key != null) {
return key;
}
}
Class<?> parent = clazz.getSuperclass();
if (parent != null) {
return findKeyForClass(domain, parent);
}
return null;
}
}