/*
* Milyn - Copyright (C) 2006 - 2010
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License (version 2.1) as published by the Free Software
* Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU Lesser General Public License for more details:
* http://www.gnu.org/licenses/lgpl.txt
*/
package org.milyn.edi.test;
import org.milyn.edisax.model.internal.Delimiters;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
/**
* This utility class manufactures test messages by reflectively constructing the messages.
*
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
*/
public class MessageBuilder {
private String packageScope;
private String delimiterForEscaping;
private Delimiters delimiters;
public MessageBuilder(String packageScope, String delimiterForEscaping, Delimiters delimiters) {
this.packageScope = packageScope;
this.delimiterForEscaping = delimiterForEscaping;
this.delimiters = delimiters;
}
public Delimiters getDelimiters() {
return delimiters;
}
public <T> T buildMessage(Class<T> messageType) {
try {
return buildObject(messageType, null);
} catch (Exception e) {
throw new IllegalArgumentException("Unable to construct an instance of '" + messageType.getName() + "'", e);
}
}
private <T> T buildObject(Class<T> objectType, String name) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
if (objectType == Delimiters.class) {
return objectType.cast(delimiters);
}
//
// Assumptions...
// 1. Either a Number, String or a type inside the packageScope of the constructing
// packageScope package
// 2. If a primitive Number... it's an int
//
if (String.class.isAssignableFrom(objectType)) {
// Return the object name as the
// string value... with a delimiter in it to test
// escaping of delims...
return objectType.cast(name + delimiterForEscaping + name);
} else if (Number.class.isAssignableFrom(objectType)) {
return objectType.getConstructor(String.class).newInstance("1.1");
} else if (int.class.isAssignableFrom(objectType)) {
return (T) new Integer(1);
} else if (objectType == Object.class) {
// don't construct raw Object types... leave them and just return null...
return null;
}
// Make sure the object is within the package packageScope...
if (!objectType.getPackage().getName().startsWith(packageScope)) {
throw new InstantiationException("Cannot create instance of type '" + objectType.getName() + "'. Not inside the scope of package '" + packageScope + "'");
}
T messageInstance = objectType.newInstance();
// populate all the fields...
Method[] methods = objectType.getMethods();
for (Method method : methods) {
if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) {
Class<?> propertyType = method.getParameterTypes()[0];
Object propertyInstance = null;
if (List.class.isAssignableFrom(propertyType)) {
Type genericType = method.getGenericParameterTypes()[0];
if (genericType instanceof ParameterizedType) {
List list = new ArrayList();
ParameterizedType genericTypeClass = (ParameterizedType) genericType;
list.add(buildObject((Class<Object>) genericTypeClass.getActualTypeArguments()[0], method.getName().substring(3)));
propertyInstance = list;
}
} else {
propertyInstance = buildObject(propertyType, method.getName().substring(3));
}
if (propertyInstance != null) {
method.invoke(messageInstance, propertyInstance);
}
}
}
return messageInstance;
}
}