producer performance upgrades in the form of entity caching, and preliminary
[mir.git] / source / mir / generator / FreemarkerGenerator.java
1 package mir.generator;
2
3 import java.util.*;
4 import java.io.*;
5 import freemarker.template.*;
6 import mir.entity.*;
7 import mir.util.*;
8 import mir.misc.*;
9 import org.apache.struts.util.MessageResources;
10
11 public class FreemarkerGenerator implements Generator {
12   private Template template;
13
14   public FreemarkerGenerator(Template aTemplate) {
15     template = aTemplate;
16   }
17
18   public void generate(PrintWriter anOutputWriter, Map aValues, PrintWriter aLogger) throws GeneratorException {
19     try {
20                   template.process((TemplateModelRoot) makeMapAdapter(aValues), anOutputWriter);
21     }
22     catch (Throwable t) {
23       aLogger.println("Exception occurred: "+t.getMessage());
24       t.printStackTrace(aLogger);
25     }
26         }
27
28   private static TemplateScalarModel makeStringAdapter(String aString) {
29     return new SimpleScalar(aString);
30   }
31
32   private static TemplateHashModel makeMapAdapter(Map aMap)  {
33     return new MapAdapter(aMap);
34   }
35
36   private static TemplateListModel makeIteratorAdapter(Iterator anIterator) {
37     return new IteratorAdapter(anIterator);
38   }
39
40         private static TemplateModel makeAdapter(Object anObject) throws TemplateModelException {
41           if (anObject == null)
42             return null;
43           if (anObject instanceof TemplateModel)
44             return (TemplateModel) anObject;
45 //        if (anObject instanceof Date)
46 //          return new DateAdapter((Date) anObject);
47           else if (anObject instanceof MessageResources)
48             return new MessageMethodModel((MessageResources) anObject);
49           else if (anObject instanceof String)
50             return makeStringAdapter((String) anObject);
51           else if (anObject instanceof Map)
52             return makeMapAdapter((Map) anObject);
53           else if (anObject instanceof Iterator)
54             return makeIteratorAdapter((Iterator) anObject);
55           else if (anObject instanceof List)
56             return makeIteratorAdapter(((List) anObject).iterator());
57           else
58             throw new TemplateModelException("Unadaptable class: " + anObject.getClass().getName());
59         }
60
61         private static class MapAdapter implements TemplateModelRoot {
62           Map map;
63           Map valuesCache;
64
65           private MapAdapter(Map aMap) {
66             map = aMap;
67             valuesCache = new HashMap();
68           }
69
70           public void put(String aKey, TemplateModel aModel) {
71             valuesCache.put(aKey, aModel);
72           }
73
74           public void remove(String aKey) {
75             // ML: kinda tricky...
76           }
77
78           public boolean isEmpty() {
79             return map.isEmpty();
80           }
81
82           public TemplateModel get(String aKey) throws TemplateModelException {
83             if (!valuesCache.containsKey(aKey)) {
84               Object value = map.get(aKey);
85
86 //    ML: this unfortunately doesn't work, because the entity doesn't seem to store
87 //        fields with null values
88 //    if (value == null && !map.containsKey(aKey))
89 //          throw new TemplateModelException("MapAdapter: no key "+aKey+" available");
90
91               valuesCache.put(aKey, makeAdapter(value));
92             }
93
94             return (TemplateModel) valuesCache.get(aKey);
95           }
96         }
97
98         private static class IteratorAdapter implements TemplateListModel {
99           Iterator iterator;
100           List valuesCache;
101           int position;
102
103           private IteratorAdapter(Iterator anIterator) {
104             iterator = anIterator;
105
106             valuesCache = new Vector();
107             position=0;
108
109
110             if (iterator instanceof RewindableIterator) {
111               ((RewindableIterator) iterator).rewind();
112             }
113           }
114
115           public boolean isEmpty() {
116             return valuesCache.isEmpty() && !iterator.hasNext();
117           }
118
119           private void getUntil(int anIndex) throws TemplateModelException {
120             while (valuesCache.size()<=anIndex && iterator.hasNext())
121             {
122               valuesCache.add(makeAdapter(iterator.next()));
123             }
124           };
125
126           public TemplateModel get(int anIndex) throws TemplateModelException {
127             TemplateModel result;
128
129             getUntil(anIndex);
130
131             if (anIndex<valuesCache.size())
132             {
133               result = (TemplateModel) valuesCache.get(anIndex);
134
135               return result;
136             }
137             else
138               throw new TemplateModelException( "Iterator out of bounds" );
139           }
140
141     public boolean hasNext() {
142       return position<valuesCache.size() || iterator.hasNext();
143     }
144
145     public boolean isRewound() {
146       return position==0;
147     }
148
149     public TemplateModel next() throws TemplateModelException {
150       TemplateModel result;
151
152       if (hasNext()) {
153         result = get(position);
154         position++;
155       }
156       else
157               throw new TemplateModelException( "Iterator out of bounds" );
158
159       return result;
160     }
161
162     public void rewind() {
163       position=0;
164     }
165         }
166
167         private static class ListAdapter implements TemplateListModel {
168           List list;
169           List valuesCache;
170           int position;
171
172           private ListAdapter(List aList) {
173             list = aList;
174             valuesCache = new Vector();
175             position=0;
176           }
177
178           public boolean isEmpty() {
179             return list.isEmpty();
180           }
181
182           public TemplateModel get(int i) throws TemplateModelException {
183
184             if (i>=valuesCache.size() && i<list.size()) {
185               for(int j=valuesCache.size(); j<=i; j++) {
186                 valuesCache.add(makeAdapter(list.get(j)));
187               }
188             }
189
190             if (i<valuesCache.size())
191               return (TemplateModel) valuesCache.get(i);
192             else
193               throw new TemplateModelException( "Iterator out of bounds" );
194           }
195
196     public boolean hasNext() {
197       return position<list.size();
198     }
199
200     public boolean isRewound() {
201       return position==0;
202     }
203
204     public TemplateModel next() throws TemplateModelException {
205       TemplateModel result;
206
207       if (hasNext()) {
208         result = get(position);
209         position++;
210       }
211             else
212               throw new TemplateModelException( "Iterator out of bounds" );
213
214       return result;
215     }
216
217     public void rewind() {
218       position=0;
219     }
220         }
221
222 /*      private static class DateAdapter implements TemplateHashModel {
223           Date date;
224
225           private DateAdapter(Date aDate) {
226             date = aDate;
227           }
228
229           public boolean isEmpty() {
230             return false;
231           }
232
233           public TemplateModel get(String aKey) throws TemplateModelException {
234             return makeAdapter(new SimpleDateFormat(aKey).format(date));
235           }
236         }
237 */
238 }