OK. Necessity is mother of invention!
I decide to implement an ApplicationContext subclass that get some templates (of spring XML configuration files using FreeMarker syntax) and some config objects of data (usually maps that store objects with names referred in templates).
I name this class XmlTemplateApplicationContext (below code).
It fills templates with config objects and produces concrete XML configurations. But after loading them and calling refresh() has an odd behavior:
A bean defined in templates, sometimes exists and sometimes no (exactly every other time).
Code:
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.security.util.InMemoryResource;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
/**
* @author mjafari
*
*/
public class XmlTemplateApplicationContext extends AbstractXmlApplicationContext {
private Map<String, Resource> typeToTemplate = null;
private Resource[] templates;
private Resource[] filledTemplates;
private Resource[] allResources;
/**
* @param resources
*/
public XmlTemplateApplicationContext(Resource[] templates, Object[] configs, Resource[] resources) {
super();
this.templates = templates;
filledTemplates = new Resource[configs.length];
String filledTemplate;
Map<String, Object> model = new HashMap<String, Object>(1);
for(int i = 0; i < configs.length; i++){
try {
model.put("configh", configs[i]);
filledTemplate = FreeMarkerTemplateUtils.processTemplateIntoString(getTemplate(configs[i]), model);
filledTemplates[i] = new InMemoryResource(filledTemplate);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (TemplateException e) {
throw new RuntimeException(e);
}
}
allResources = concat(filledTemplates, resources);
refresh();
}
@Override
protected Resource[] getConfigResources() {
return allResources;
}
protected Template getTemplate(Object config) throws IOException {
if (typeToTemplate == null) {
typeToTemplate = new HashMap<String, Resource>(
templates.length);
for (Resource resource : templates) {
typeToTemplate.put(resource.getFilename(), resource);
}
}
Map<String, String> configMap = (Map) config;
String name = configMap.get("type");
return new Template(name, new InputStreamReader(typeToTemplate.get(name).getInputStream()), new Configuration());
}
private <T> T[] concat(T[] array1, T[] array2){
@SuppressWarnings("unchecked")
T[] result = (T[]) Array.newInstance(array1.getClass().getComponentType(), array1.length + array2.length);
System.arraycopy(array1, 0, result, 0, array1.length);
System.arraycopy(array2, 0, result, array1.length, array2.length);
return result;
}