3 import freemarker.template.*;
4 import org.apache.struts.util.MessageResources;
11 public class FreemarkerGenerator implements Generator {
12 private Template template;
14 public FreemarkerGenerator(Template aTemplate) {
18 public void generate(Object anOutputWriter, Map aValues, PrintWriter aLogger) throws GeneratorExc, GeneratorFailure {
19 if (!(anOutputWriter instanceof PrintWriter))
20 throw new GeneratorExc("Writer for a FreemarkerGenerator must be a PrintWriter");
23 template.process((TemplateModelRoot) makeMapAdapter(aValues), (PrintWriter) anOutputWriter);
26 aLogger.println("Exception occurred: "+t.getMessage());
27 t.printStackTrace(aLogger);
28 throw new GeneratorFailure( t );
32 private static TemplateScalarModel makeStringAdapter(String aString) {
33 return new SimpleScalar(aString);
36 private static TemplateHashModel makeMapAdapter(Map aMap) {
37 return new MapAdapter(aMap);
40 private static TemplateListModel makeIteratorAdapter(Iterator anIterator) {
41 return new IteratorAdapter(anIterator);
44 private static TemplateMethodModel makeFunctionAdapter(Generator.GeneratorFunction aFunction) {
45 return new FunctionAdapter(aFunction);
48 private static TemplateModel makeAdapter(Object anObject) throws TemplateModelException {
51 if (anObject instanceof TemplateModel)
52 return (TemplateModel) anObject;
53 else if (anObject instanceof Generator.GeneratorFunction)
54 return makeFunctionAdapter((Generator.GeneratorFunction) anObject);
55 else if (anObject instanceof MessageResources)
56 return new MessageMethodModel((MessageResources) anObject);
57 else if (anObject instanceof Integer)
58 return makeStringAdapter(((Integer) anObject).toString());
59 else if (anObject instanceof String)
60 return makeStringAdapter((String) anObject);
61 else if (anObject instanceof Map)
62 return makeMapAdapter((Map) anObject);
63 else if (anObject instanceof Iterator)
64 return makeIteratorAdapter((Iterator) anObject);
65 else if (anObject instanceof List)
66 return makeIteratorAdapter(((List) anObject).iterator());
68 throw new TemplateModelException("Unadaptable class: " + anObject.getClass().getName());
71 private static class MapAdapter implements TemplateModelRoot {
75 private MapAdapter(Map aMap) {
77 valuesCache = new HashMap();
80 public void put(String aKey, TemplateModel aModel) {
81 valuesCache.put(aKey, aModel);
84 public void remove(String aKey) {
85 // ML: kinda tricky...
88 public boolean isEmpty() {
92 public TemplateModel get(String aKey) throws TemplateModelException {
94 if (!valuesCache.containsKey(aKey)) {
95 Object value = map.get(aKey);
97 if (value == null && !map.containsKey(aKey))
98 throw new TemplateModelException("MapAdapter: no key "+aKey+" available");
100 valuesCache.put(aKey, makeAdapter(value));
103 return (TemplateModel) valuesCache.get(aKey);
105 catch (TemplateModelException e) {
108 catch (Throwable t) {
109 throw new TemplateModelException(t.getMessage());
114 private static class IteratorAdapter implements TemplateListModel {
119 private IteratorAdapter(Iterator anIterator) {
120 iterator = anIterator;
122 valuesCache = new Vector();
126 if (iterator instanceof RewindableIterator) {
127 ((RewindableIterator) iterator).rewind();
131 public boolean isEmpty() {
132 return valuesCache.isEmpty() && !iterator.hasNext();
135 private void getUntil(int anIndex) throws TemplateModelException {
136 while (valuesCache.size()<=anIndex && iterator.hasNext())
138 valuesCache.add(makeAdapter(iterator.next()));
142 public TemplateModel get(int anIndex) throws TemplateModelException {
143 TemplateModel result;
147 if (anIndex<valuesCache.size())
149 result = (TemplateModel) valuesCache.get(anIndex);
154 throw new TemplateModelException( "Iterator out of bounds" );
157 public boolean hasNext() {
158 return position<valuesCache.size() || iterator.hasNext();
161 public boolean isRewound() {
165 public TemplateModel next() throws TemplateModelException {
166 TemplateModel result;
169 result = get(position);
173 throw new TemplateModelException( "Iterator out of bounds" );
178 public void rewind() {
183 private static class ListAdapter implements TemplateListModel {
188 private ListAdapter(List aList) {
190 valuesCache = new Vector();
194 public boolean isEmpty() {
195 return list.isEmpty();
198 public TemplateModel get(int i) throws TemplateModelException {
200 if (i>=valuesCache.size() && i<list.size()) {
201 for(int j=valuesCache.size(); j<=i; j++) {
202 valuesCache.add(makeAdapter(list.get(j)));
206 if (i<valuesCache.size())
207 return (TemplateModel) valuesCache.get(i);
209 throw new TemplateModelException( "Iterator out of bounds" );
212 public boolean hasNext() {
213 return position<list.size();
216 public boolean isRewound() {
220 public TemplateModel next() throws TemplateModelException {
221 TemplateModel result;
224 result = get(position);
228 throw new TemplateModelException( "Iterator out of bounds" );
234 public void rewind() {
239 private static class FunctionAdapter implements TemplateMethodModel {
240 Generator.GeneratorFunction function;
242 public FunctionAdapter(Generator.GeneratorFunction aFunction) {
243 function = aFunction;
246 public TemplateModel exec(List anArguments) throws TemplateModelException {
248 return makeAdapter(function.perform(anArguments));
250 catch (Throwable t) {
251 throw new TemplateModelException(t.getMessage());
255 public boolean isEmpty() {
261 public static class FreemarkerGeneratorLibrary implements GeneratorLibrary {
262 private FileTemplateCache templateCache;
264 public FreemarkerGeneratorLibrary(String aTemplateRoot) {
265 templateCache = new FileTemplateCache( aTemplateRoot + "/" );
266 templateCache.setLoadingPolicy(templateCache.LOAD_ON_DEMAND);
269 public Generator makeGenerator(String anIdentifier) throws GeneratorExc, GeneratorFailure {
270 Template template = (Template) templateCache.getItem(anIdentifier, "template");
272 if (template==null) {
273 throw new GeneratorExc("FreemarkerGeneratorLibrary: Can't find template "+templateCache.getDirectory()+anIdentifier);
276 return new FreemarkerGenerator(template);