package rtt.core.testing.generation;
import java.lang.reflect.Array;
import java.net.MalformedURLException;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import rtt.annotations.processing.AnnotationProcessor;
import rtt.annotations.processing.ValueMember;
import rtt.core.archive.configuration.Configuration;
import rtt.core.archive.input.Input;
import rtt.core.archive.output.Element;
import rtt.core.archive.output.ElementType;
import rtt.core.archive.output.GeneratorType;
import rtt.core.archive.output.Output;
import rtt.core.utils.ExecutorLoader;
import rtt.core.utils.RTTLogging;
public class DataGenerator {
private Map<Object, String> objectAddresses;
private DataGenerator() {
objectAddresses = new Hashtable<>();
}
private Element createElement(String address, String name,
GeneratorType generatedBy, boolean informational) {
Element element = new Element();
element.setAddress(address);
element.setName(name);
element.setInformational(informational);
element.setGeneratedBy(generatedBy);
return element;
}
private void handleResult(final Object object, Element element)
throws ReflectiveOperationException {
if (object != null) {
Class<?> objectType = object.getClass();
element.setReturnType(objectType.getName());
if (objectAddresses.containsKey(object)) {
element.setElementType(ElementType.REFERENCE);
element.setValue(objectAddresses.get(object));
} else {
if (AnnotationProcessor.isNode(object)) {
objectAddresses.put(object, element.getAddress());
element.setElementType(ElementType.NODE);
element.setValue(objectType.getName());
handleNode(object, element);
}
if (element.getElements().isEmpty()) {
if (objectType.isArray()) {
element.setElementType(ElementType.NODE);
element.setValue(objectType.getSimpleName());
handleArray(object, element);
} else if (object instanceof Iterable<?>) {
element.setElementType(ElementType.NODE);
element.setValue(objectType.getName());
handleIterable((Iterable<?>) object, element);
} else if (object instanceof Map<?, ?>) {
element.setElementType(ElementType.NODE);
element.setValue(objectType.getName());
handleMap((Map<?, ?>) object, element);
}
}
if (element.getValue() == null) {
element.setElementType(ElementType.VALUE);
element.setValue(object.toString());
}
}
}
}
private void handleNode(final Object object, Element element)
throws ReflectiveOperationException {
Set<ValueMember<?>> annotatedElements =
AnnotationProcessor.getValueMembers(object.getClass());
Element childElement = null;
String address = null;
int childAddress = 1;
for (ValueMember<?> annotatedElement : annotatedElements) {
address = element.getAddress() + "." + childAddress;
childElement = createElement(address,
annotatedElement.getName(),
annotatedElement.getType(),
element.isInformational() || annotatedElement.isInformational());
element.getElements().add(childElement);
childElement.setReturnType(annotatedElement.getReturnType());
handleResult(annotatedElement.getResult(object), childElement);
childAddress++;
}
}
private void handleArray(final Object array, Element element)
throws ReflectiveOperationException {
Element childElement = null;
String address = null;
String name = null;
for (int index = 1; index - 1 < Array.getLength(array); index++) {
address = element.getAddress() + "." + index;
name = element.getName() + "[" + index + "]";
childElement = createElement(address, name,
GeneratorType.ARRAY, element.isInformational());
element.getElements().add(childElement);
childElement.setReturnType(element.getName());
handleResult(Array.get(array, index - 1), childElement);
}
}
private void handleIterable(final Iterable<?> iterable, Element element)
throws ReflectiveOperationException {
int index = 1;
Element childElement = null;
String address = null;
String name = null;
for (Object object : iterable) {
address = element.getAddress() + "." + index;
name = element.getName() + "[" + index + "]";
childElement = createElement(address, name,
GeneratorType.ITERABLE, element.isInformational());
element.getElements().add(childElement);
childElement.setReturnType(object.getClass().getName());
handleResult(object, childElement);
index++;
}
}
private void handleMap(final Map<?, ?> map, Element element)
throws ReflectiveOperationException {
final boolean isInformational = element.isInformational();
int entryIndex = 1;
Element entryElement = null;
Element keyElement = null;
Element valueElement = null;
Object keyItem = null;
Object valueItem = null;
String address = null;
String name = null;
for (Entry<?, ?> mapEntry : map.entrySet()) {
address = element.getAddress() + "." + entryIndex;
name = element.getName() + " [" + entryIndex + "]";
entryElement = createElement(address, name,
GeneratorType.MAP, isInformational);
// add an element representing the key
keyItem = mapEntry.getKey();
keyElement = createElement(address, name + "-Key",
GeneratorType.MAP, isInformational);
keyElement.setValue(keyItem.getClass().getSimpleName());
handleResult(mapEntry.getKey(), keyElement);
entryElement.getElements().add(keyElement);
// add an element representing the value
valueItem = mapEntry.getValue();
valueElement = createElement(address, name + "-Value",
GeneratorType.MAP, isInformational);
valueElement.setValue(valueItem.getClass().getSimpleName());
handleResult(mapEntry.getValue(), valueElement);
entryElement.getElements().add(valueElement);
element.getElements().add(entryElement);
entryIndex++;
}
}
public static Output generateOutput(Input input, List<String> params,
Executor executor) throws Throwable {
if (input == null || params == null || executor == null) {
throw new IllegalArgumentException("One argument was null.");
}
Output outputData = new Output();
Object initObject = null;
try {
RTTLogging.debug("Initial object type: " +
executor.getInitialObjectType().getSimpleName());
initObject = executor.initialize(input, params);
} catch (ReflectiveOperationException exception) {
Throwable cause = exception.getCause();
if (!executor.isAcceptedException(cause)) {
throw cause;
} else {
throw new UnsupportedOperationException(
"Accepted exception are currently not supported.", cause);
}
}
RTTLogging.debug("Generating output data ...");
DataGenerator generator = new DataGenerator();
Element initElement = generator.createElement(
"1", "Initial Node", GeneratorType.OBJECT, false);
try {
generator.handleResult(initObject, initElement);
} catch (ReflectiveOperationException exception) {
Throwable cause = exception.getCause();
if (!executor.isAcceptedException(cause)) {
throw cause;
} else {
throw new UnsupportedOperationException(
"Accepted exception are currently not supported.", cause);
}
}
outputData.setInitialElement(initElement);
return outputData;
}
/**
* <p>Tries to locate the {@link Executor} via the class loader</p>
*
* <p>Instantiate the executor through
* {@link Executor#generateInitialObject(Input, List)} before use!</p>
*
* @param config the {@link Configuration}
* @param baseDir the base directory for searching
* @return a {@link Executor} or null (if config is empty)
* @throws MalformedURLException mainly exceptions during class loading
* @throws ClassNotFoundException mainly exceptions during class loading
*/
public static Executor locateInitialNode(Configuration config,
String baseDir) throws MalformedURLException, ClassNotFoundException {
String initialNode = config.getInitialNode();
if (initialNode == null || initialNode.trim().isEmpty()) {
throw new IllegalStateException("The given configuration contains no initial node.");
}
RTTLogging.info("Initial Node: " + initialNode);
ExecutorLoader loader = new ExecutorLoader(config.getClasspath(), baseDir);
return new Executor(loader.resolveClass(initialNode.trim()));
}
}