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