package ch.nerdin.generators.testdata.util;
import freemarker.core.Environment;
import freemarker.ext.beans.BeanModel;
import freemarker.ext.beans.CollectionModel;
import freemarker.ext.beans.StringModel;
import freemarker.template.*;
import ch.nerdin.generators.testdata.BeanFactory;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.persistence.Column;
import java.io.*;
import java.util.*;
/**
* @author edewit
*/
public class DataSetGenerator {
private static final Logger logger = LoggerFactory.getLogger(DataSetGenerator.class.getName());
private static BeanFactory beanFactory;
private static Configuration configuration;
static {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-beangenerator.xml");
beanFactory = (BeanFactory) context.getBean("beanFactory");
configuration = new Configuration();
configuration.setClassForTemplateLoading(DataSetGenerator.class, "/");
configuration.setObjectWrapper(new DefaultObjectWrapper());
}
public static void main(String... arg) throws ClassNotFoundException, IOException, TemplateException {
if (arg.length < 1) {
System.err.println("usage: " + DataSetGenerator.class + " the.entity.bean.ToGenerateDataSetFor outputFile");
}
Class<?> beanClass = Class.forName(arg[0]);
String xml = generateDataSet(beanClass);
if (arg.length == 2) {
FileOutputStream fos = new FileOutputStream(new File(arg[1]));
try {
fos.write(xml.getBytes(), 0, xml.getBytes().length);
} finally {
fos.close();
}
} else {
System.out.println(xml);
}
}
public static String generateDataSet(Class<?> beanClass) throws IOException, TemplateException {
List<Object> beans = new ArrayList<Object>();
for(int i = 0; i < 10; i++) {
beans.add(beanFactory.instantiateBean(beanClass));
}
Map<String, Object> root = new HashMap<String, Object>();
root.put("beans", beans);
root.put("invokeBean", new DynamicList());
root.put("invokeMethod", new DynamicMethod());
Template temp = configuration.getTemplate("dataset.ftl");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
Writer out = new OutputStreamWriter(new BufferedOutputStream(stream));
temp.process(root, out);
out.flush();
return stream.toString();
}
private static abstract class DynamicProperty implements TemplateDirectiveModel {
protected Object invokeMethod(Map map) {
String method = ((SimpleScalar) map.get("method")).getAsString();
Object bean = ((BeanModel)map.get("bean")).getWrappedObject();
Object property = null;
try {
if (PropertyUtils.isReadable(bean, method)) {
property = PropertyUtils.getProperty(bean, method);
}
} catch (Exception e) {
logger.warn("Error calling {} on bean {}", method, bean.getClass());
}
return property;
}
}
private static class DynamicList extends DynamicProperty {
public void execute(Environment environment, Map map, TemplateModel[] templateModels,
TemplateDirectiveBody templateDirectiveBody) throws TemplateException, IOException {
Object property = invokeMethod(map);
String alias = ((SimpleScalar) map.get("alias")).getAsString();
CollectionModel list = (CollectionModel) environment.getVariable(alias);
ArrayList<Object> result = new ArrayList<Object>();
if (list != null) {
TemplateModelIterator iterator = list.iterator();
while (iterator.hasNext()) {
Object o = iterator.next();
result.add(o);
}
}
if (property instanceof Collection) {
result.addAll((Collection<?>) property);
} else {
result.add(property);
}
environment.setVariable(alias, new CollectionModel(result, new DefaultObjectWrapper()));
}
}
private static class DynamicMethod extends DynamicProperty {
public void execute(Environment environment, Map map, TemplateModel[] templateModels,
TemplateDirectiveBody templateDirectiveBody) throws TemplateException, IOException {
Object property = invokeMethod(map);
if (property != null) {
String propertyName = ((SimpleScalar) map.get("method")).getAsString();
Class beanClass = (Class) ((StringModel)environment.getVariable("beanClass")).getWrappedObject();
try {
final Column annotation = beanClass.getDeclaredField(propertyName).getAnnotation(Column.class);
if (annotation != null && StringUtils.isNotBlank(annotation.name())) {
propertyName = annotation.name();
}
} catch (NoSuchFieldException e) {
logger.error("no such field {} on bean of type {}", propertyName, beanClass);
}
environment.getOut().append(propertyName)
.append("=\"").append(String.valueOf(property)).append("\" ");
}
}
}
}