fb3b612a63fa80b9695a0ae31ed85b49f17e3541
[mir.git] / source / mir / misc / HTMLTemplateProcessor.java
1 /*\r
2  * Copyright (C) 2001, 2002  The Mir-coders group\r
3  *\r
4  * This file is part of Mir.\r
5  *\r
6  * Mir is free software; you can redistribute it and/or modify\r
7  * it under the terms of the GNU General Public License as published by\r
8  * the Free Software Foundation; either version 2 of the License, or\r
9  * (at your option) any later version.\r
10  *\r
11  * Mir is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License\r
17  * along with Mir; if not, write to the Free Software\r
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19  *\r
20  * In addition, as a special exception, The Mir-coders gives permission to link\r
21  * the code of this program with the com.oreilly.servlet library, any library\r
22  * licensed under the Apache Software License, The Sun (tm) Java Advanced\r
23  * Imaging library (JAI), The Sun JIMI library (or with modified versions of\r
24  * the above that use the same license as the above), and distribute linked\r
25  * combinations including the two.  You must obey the GNU General Public\r
26  * License in all respects for all of the code used other than the above\r
27  * mentioned libraries.  If you modify this file, you may extend this exception\r
28  * to your version of the file, but you are not obligated to do so.  If you do\r
29  * not wish to do so, delete this exception statement from your version.\r
30  */\r
31 \r
32 package mir.misc;\r
33 \r
34 import freemarker.template.*;\r
35 import mir.util.*;\r
36 import mir.generator.*;\r
37 import mir.entity.Entity;\r
38 import mir.entity.EntityList;\r
39 import mir.storage.StorageObjectException;\r
40 import org.apache.struts.util.MessageResources;\r
41 \r
42 import javax.servlet.http.HttpServletResponse;\r
43 import java.io.PrintWriter;\r
44 import java.net.URLEncoder;\r
45 import java.util.*;\r
46 \r
47 \r
48 /**\r
49  * Hilfsklasse zum Mergen von Template und Daten\r
50  */\r
51 public final class HTMLTemplateProcessor {\r
52 \r
53   public static String templateDir;\r
54   private static FileTemplateCache templateCache;\r
55   private static Logfile theLog;\r
56   private static String docRoot;\r
57   private static String actionRoot;\r
58 \r
59   static {\r
60     templateDir = MirConfig.getPropWithHome("HTMLTemplateProcessor.Dir");\r
61     templateCache = new FileTemplateCache(templateDir);\r
62     templateCache.setLoadingPolicy(templateCache.LOAD_ON_DEMAND);\r
63     // gone in freemarker 1.7.1: templateCache.startAutoUpdate();\r
64     theLog = Logfile.getInstance(MirConfig.getPropWithHome(\r
65         "HTMLTemplateProcessor.Logfile"));\r
66 \r
67     docRoot = MirConfig.getProp("RootUri");\r
68     try {\r
69       actionRoot = docRoot + MirConfig.getProp("Producer.ActionServlet");\r
70     }\r
71     catch (ConfigException ce) {\r
72       // if  Producer.ActionServlet is not set in the conf file\r
73       actionRoot = docRoot + "/Mir";\r
74     }\r
75   }\r
76 \r
77   /**\r
78    * empty private constructor, to avoid instantiation\r
79    */\r
80   private HTMLTemplateProcessor() {\r
81   }\r
82 \r
83   // process-methods to merge different datastructures\r
84   // with freemarker templates\r
85 \r
86   /**\r
87        * Wandelt <code>anEntity</code> in freemarker-Struktur um, mischt die Daten mit\r
88    * Template <code>templateFilename</code> und gibt das Ergebnis an den PrintWriter\r
89    * <code>out</code>\r
90    *\r
91    * @param templateFilename\r
92    * @param anEntity\r
93    * @param out\r
94    * @exception HTMLParseException\r
95    */\r
96 \r
97   public static void process(String templateFilename, Entity anEntity,\r
98                              PrintWriter out) throws HTMLParseException {\r
99     if (anEntity == null)\r
100       throw new HTMLParseException("entity is empty!");\r
101     else\r
102       process(templateFilename, anEntity, out);\r
103   }\r
104 \r
105   /**\r
106    * Wandelt Liste mit Entities <code>entList</code> in freemarker-Struktur um, mischt die Daten mit\r
107    * Template <code>templateFilename</code> und gibt das Ergebnis an den PrintWriter\r
108    * <code>out</code>\r
109    *\r
110    * @param templateFilename\r
111    * @param entList\r
112    * @param out\r
113    * @exception HTMLParseException\r
114    */\r
115   public static void process(HttpServletResponse res, String templateFilename,\r
116    EntityList entList, PrintWriter out, Locale locale) throws HTMLParseException {\r
117     process(res, templateFilename, entList, (String)null, (TemplateModelRoot)null,\r
118             out, locale);\r
119   }\r
120 \r
121   /**\r
122    * Wandelt Entitylist in freemarker-Struktur um, fügt <code>additionalModel</code>\r
123        * unter dem Namen <code>additionalModelName</code> ein und mischt die Daten mit\r
124    * Template <code>templateFilename</code> und gibt das Ergebnis an den PrintWriter\r
125    * <code>out</code>\r
126    *\r
127    * @param templateFilename\r
128    * @param entList\r
129    * @param additionalModelName\r
130    * @param additionalModel\r
131    * @param out\r
132    * @exception HTMLParseException\r
133    */\r
134   public static void process(HttpServletResponse res, String templateFilename,\r
135                              EntityList entList, String additionalModelName,\r
136                              TemplateModelRoot additionalModel, PrintWriter out,\r
137                              Locale locale) throws HTMLParseException {\r
138 \r
139     SimpleHash modelRoot = new SimpleHash();\r
140 \r
141     if (entList == null) {\r
142       process(null, templateFilename, modelRoot, out, locale);\r
143     }\r
144     else {\r
145       try {\r
146         modelRoot = makeSimpleHashWithEntitylistInfos(entList);\r
147 \r
148         // Quickhack um mal ein Popup mit reinzunhemen ..\r
149         if (additionalModelName != null && additionalModel != null)\r
150           modelRoot.put(additionalModelName, additionalModel);\r
151 \r
152         process(res, templateFilename, modelRoot, out, locale);\r
153       }\r
154       catch (StorageObjectException e) {\r
155         throw new HTMLParseException(e.toString());\r
156       }\r
157     }\r
158   }\r
159 \r
160   /**\r
161    * Gibt Template <code>templateFilename</code> an den PrintWriter\r
162    * <code>out</code>\r
163    *\r
164    * @param templateFilename\r
165    * @param mergeData\r
166    * @param out\r
167    * @exception HTMLParseException\r
168    */\r
169   public static void process(String templateFilename, PrintWriter out,\r
170                              Locale locale) throws HTMLParseException {\r
171     process(null, templateFilename, (TemplateModelRoot)null, out, locale);\r
172   }\r
173 \r
174   /**\r
175    * Mischt die freemarker-Struktur <code>tmr</code> mit\r
176    * Template <code>templateFilename</code> und gibt das Ergebnis an den PrintWriter\r
177    * <code>out</code>\r
178    *\r
179    * @param templateFilename\r
180    * @param mergeData\r
181    * @param out\r
182    * @exception HTMLParseException\r
183    */\r
184   public static void process(HttpServletResponse res, String templateFilename,\r
185                              TemplateModelRoot tmr, PrintWriter out,\r
186                              Locale locale) throws HTMLParseException {\r
187     process(res, templateFilename, tmr, null, out, locale);\r
188   }\r
189 \r
190   public static void process(HttpServletResponse res, String templateFilename,\r
191                              TemplateModelRoot tmr, TemplateModelRoot extra,\r
192                              PrintWriter out, Locale locale) throws HTMLParseException {\r
193     process(res, templateFilename, tmr, extra, out, locale, "bundles.adminlocal", "bundles.admin");\r
194   }\r
195 \r
196   public static void process(HttpServletResponse res, String templateFilename,\r
197        TemplateModelRoot tmr, TemplateModelRoot extra, PrintWriter out,\r
198        Locale locale, String bundles) throws HTMLParseException {\r
199     process(res, templateFilename, tmr, extra, out, locale, bundles, null);\r
200   }\r
201 \r
202   /**\r
203    * Mischt die freemarker-Struktur <code>tmr</code> mit\r
204    * Template <code>templateFilename</code> und gibt das Ergebnis an den PrintWriter\r
205    * <code>out</code>\r
206    *\r
207    * @param templateFilename\r
208    * @param mergeData\r
209    * @param out\r
210    * @exception HTMLParseException\r
211    */\r
212   public static void process(HttpServletResponse res, String templateFilename,\r
213                              TemplateModelRoot tmr, TemplateModelRoot extra,\r
214                              PrintWriter out, Locale locale, String bundles,\r
215                              String bundles2) throws\r
216       HTMLParseException {\r
217     if (out == null)\r
218       throw new HTMLParseException("no outputstream");\r
219     Template tmpl = getTemplateFor(templateFilename);\r
220     if (tmpl == null)\r
221       throw new HTMLParseException("no template: " + templateFilename);\r
222     if (tmr == null)\r
223       tmr = new SimpleHash();\r
224 \r
225       /** @todo  what is this for? (rk) */\r
226     String session = "";\r
227     if (res != null) {\r
228       session = res.encodeURL("");\r
229     }\r
230 \r
231     SimpleHash configHash = new SimpleHash();\r
232 \r
233     // pass the whole config hash to the templates\r
234     Enumeration en = MirConfig.getResourceKeys();\r
235     String key;\r
236     while (en.hasMoreElements()) {\r
237       key = (String) en.nextElement();\r
238       configHash.put(key, new SimpleScalar(MirConfig.getProp(key)));\r
239     }\r
240 \r
241     // this does not come directly from the config file\r
242     configHash.put("docRoot", new SimpleScalar(docRoot));\r
243     configHash.put("actionRoot", new SimpleScalar(actionRoot + session));\r
244     configHash.put("now",\r
245                    new SimpleScalar(StringUtil.date2readableDateTime(new GregorianCalendar())));\r
246 \r
247     // this conform to updated freemarker syntax\r
248     configHash.put("compressWhitespace",\r
249                    new freemarker.template.utility.CompressWhitespace());\r
250 \r
251     SimpleHash utilityHash = new SimpleHash();\r
252     try {\r
253       utilityHash.put("compressWhitespace",\r
254                       new freemarker.template.utility.CompressWhitespace());\r
255       utilityHash.put("encodeURI",\r
256                       FreemarkerGenerator.makeAdapter(new GeneratorHTMLFunctions.\r
257           encodeURIGeneratorFunction()));\r
258       utilityHash.put("encodeHTML",\r
259                       FreemarkerGenerator.makeAdapter(new GeneratorHTMLFunctions.\r
260           encodeHTMLGeneratorFunction()));\r
261       utilityHash.put("isOdd",\r
262                       FreemarkerGenerator.makeAdapter(new GeneratorIntegerFunctions.\r
263           isOddFunction()));\r
264       utilityHash.put("increment",\r
265                       FreemarkerGenerator.makeAdapter(new GeneratorIntegerFunctions.\r
266           incrementFunction()));\r
267     }\r
268     catch (Throwable t) {\r
269       throw new HTMLParseException(t.getMessage());\r
270     }\r
271 \r
272     SimpleHash outPutHash = new SimpleHash();\r
273 \r
274     if (extra != null) {\r
275       outPutHash.put("extra", extra);\r
276       try {\r
277         while ( ( (SimpleList) extra).hasNext()) {\r
278           theLog.printDebugInfo( ( (SimpleList) extra).next().toString());\r
279         }\r
280       }\r
281       catch (Exception e) {\r
282       }\r
283     }\r
284     outPutHash.put("data", tmr);\r
285     outPutHash.put("config", configHash);\r
286     outPutHash.put("utility", utilityHash);\r
287 \r
288     MessageResources messages = MessageResources.getMessageResources(bundles);\r
289     if (bundles2!=null) {\r
290       outPutHash.put("lang", new MessageMethodModel(locale, MessageResources.getMessageResources(bundles), MessageResources.getMessageResources(bundles2)));\r
291     }\r
292     else {\r
293       outPutHash.put("lang", new MessageMethodModel(locale, MessageResources.getMessageResources(bundles)));\r
294     }\r
295 \r
296     tmpl.process(outPutHash, out);\r
297   }\r
298 \r
299   /**\r
300    *   Converts Entity-List to SimpleList of SimpleHashes.\r
301    *   @param aList ist eine Liste von Entity\r
302    *   @return eine freemarker.template.SimpleList von SimpleHashes.\r
303    *\r
304    *    @deprecated EntityLists comply with TemplateListModel now.\r
305    */\r
306   public static SimpleList makeSimpleList(EntityList aList) throws\r
307       StorageObjectException {\r
308     theLog.printWarning(\r
309         "## using deprecated makeSimpleList(entityList) - a waste of resources");\r
310     SimpleList simpleList = new SimpleList();\r
311     if (aList != null) {\r
312       for (int i = 0; i < aList.size(); i++) {\r
313         simpleList.add(aList.elementAt(i));\r
314       }\r
315     }\r
316     return simpleList;\r
317   }\r
318 \r
319   /**\r
320    *  Konvertiert ein EntityList in ein freemarker.template.SimpleHash-Modell. Im Hash\r
321    *  sind die einzelnen Entities ueber ihre id zu erreichen.\r
322    *  @param aList ist die EntityList\r
323    *  @return SimpleHash mit den entsprechenden freemarker Daten\r
324    *\r
325    */\r
326   public static SimpleHash makeSimpleHash(EntityList aList) throws\r
327       StorageObjectException {\r
328     SimpleHash simpleHash = new SimpleHash();\r
329     Entity currentEntity;\r
330 \r
331     if (aList != null) {\r
332       for (int i = 0; i < aList.size(); i++) {\r
333         currentEntity = (Entity) aList.elementAt(i);\r
334         simpleHash.put(currentEntity.getId(), currentEntity);\r
335       }\r
336     }\r
337     return simpleHash;\r
338   }\r
339 \r
340   /**\r
341    *  Konvertiert ein Hashtable mit den keys und values als String\r
342    *  in ein freemarker.template.SimpleHash-Modell\r
343    *  @param mergeData der HashMap mit den String / String Daten\r
344    *  @return SimpleHash mit den entsprechenden freemarker Daten\r
345    *\r
346    */\r
347   public static SimpleHash makeSimpleHash(HashMap mergeData) {\r
348     SimpleHash modelRoot = new SimpleHash();\r
349     String aField;\r
350     if (mergeData != null) {\r
351       Set set = mergeData.keySet();\r
352       Iterator it = set.iterator();\r
353       for (int i = 0; i < set.size(); i++) {\r
354         aField = (String) it.next();\r
355         modelRoot.put(aField, (String) mergeData.get(aField));\r
356       }\r
357     }\r
358     return modelRoot;\r
359   }\r
360 \r
361   /**\r
362    * Converts EntityList in SimpleHash and adds additional information\r
363    * to the returned SimpleHash\r
364    *\r
365    * @param entList\r
366    * @return SimpleHash returns SimpleHash with the converted EntityList plus\r
367    *        additional Data about the list.\r
368    * @exception StorageObjectException\r
369    */\r
370 \r
371   public static SimpleHash makeSimpleHashWithEntitylistInfos(EntityList entList) throws\r
372       StorageObjectException {\r
373     SimpleHash modelRoot = new SimpleHash();\r
374     if (entList != null) {\r
375       modelRoot.put("contentlist", entList);\r
376       modelRoot.put("count",\r
377                     new SimpleScalar( (new Integer(entList.getCount())).toString()));\r
378       if (entList.getWhere() != null) {\r
379         modelRoot.put("where", new SimpleScalar(entList.getWhere()));\r
380         modelRoot.put("where_encoded",\r
381                       new SimpleScalar(URLEncoder.encode(entList.getWhere())));\r
382       }\r
383       if (entList.getOrder() != null) {\r
384         modelRoot.put("order", new SimpleScalar(entList.getOrder()));\r
385         modelRoot.put("order_encoded",\r
386                       new SimpleScalar(URLEncoder.encode(entList.getOrder())));\r
387       }\r
388       modelRoot.put("from",\r
389                     new SimpleScalar( (new Integer(entList.getFrom())).toString()));\r
390       modelRoot.put("to",\r
391                     new SimpleScalar( (new Integer(entList.getTo())).toString()));\r
392 \r
393       if (entList.hasNextBatch())\r
394         modelRoot.put("next",\r
395                       new SimpleScalar( (new Integer(entList.getNextBatch())).\r
396                                        toString()));\r
397       if (entList.hasPrevBatch())\r
398         modelRoot.put("prev",\r
399                       new SimpleScalar( (new Integer(entList.getPrevBatch())).\r
400                                        toString()));\r
401     }\r
402     return modelRoot;\r
403   }\r
404 \r
405   /**\r
406    * Private methods to get template from a templateFilename\r
407    * @param templateFilename\r
408    * @return Template\r
409    * @exception HTMLParseException\r
410    */\r
411   private static Template getTemplateFor(String templateFilename) throws\r
412       HTMLParseException {\r
413     Template returnTemplate = null;\r
414     if (templateFilename != null)\r
415       returnTemplate = (Template) templateCache.getItem(templateFilename,\r
416           "template");\r
417 \r
418     if (returnTemplate == null) {\r
419       theLog.printError("CACHE (ERR): Unknown template: " + templateFilename);\r
420       throw new HTMLParseException("Templatefile: " + templateFilename +\r
421                                    " not found.");\r
422     }\r
423 \r
424     return returnTemplate;\r
425   }\r
426 \r
427   public static void stopAutoUpdate() {\r
428     templateCache.stopAutoUpdate();\r
429     templateCache = null;\r
430   }\r
431 \r
432 }