2 * Copyright (C) 2001, 2002 The Mir-coders group
\r
4 * This file is part of Mir.
\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
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
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
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
34 import java.io.PrintWriter;
\r
35 import java.net.URLEncoder;
\r
36 import java.util.GregorianCalendar;
\r
37 import java.util.Iterator;
\r
38 import java.util.Locale;
\r
39 import java.util.Map;
\r
40 import java.util.Set;
\r
42 import javax.servlet.http.HttpServletResponse;
\r
44 import org.apache.struts.util.MessageResources;
\r
46 import freemarker.template.FileTemplateCache;
\r
47 import freemarker.template.SimpleHash;
\r
48 import freemarker.template.SimpleList;
\r
49 import freemarker.template.SimpleScalar;
\r
50 import freemarker.template.Template;
\r
51 import freemarker.template.TemplateModelRoot;
\r
53 import mir.config.MirPropertiesConfiguration;
\r
54 import mir.config.MirPropertiesConfiguration.PropertiesConfigExc;
\r
55 import mir.entity.Entity;
\r
56 import mir.entity.EntityList;
\r
57 import mir.generator.FreemarkerGenerator;
\r
58 import mir.log.LoggerWrapper;
\r
59 import mir.storage.StorageObjectFailure;
\r
60 import mir.util.GeneratorHTMLFunctions;
\r
61 import mir.util.GeneratorIntegerFunctions;
\r
65 * Hilfsklasse zum Mergen von Template und Daten
\r
67 public final class HTMLTemplateProcessor {
\r
69 public static String templateDir;
\r
70 private static final String[] bundles = { "bundles.adminlocal", "bundles.admin" };
\r
71 private static MirPropertiesConfiguration configuration;
\r
72 private static FileTemplateCache templateCache;
\r
73 private static String docRoot;
\r
74 private static String actionRoot;
\r
75 private static LoggerWrapper logger;
\r
78 // ML: configuration is not thread safe: it's risky to use it like this
\r
79 // actually I don't see why HTMLTemplateProcessor needs to be a
\r
80 // class with static methods. This causes more problems than it solves.
\r
82 configuration = MirPropertiesConfiguration.instance();
\r
84 catch (PropertiesConfigExc e) {
\r
85 e.printStackTrace();
\r
88 logger = new LoggerWrapper("TemplateEngine");
\r
91 configuration.getStringWithHome("Mir.TemplateDir");
\r
92 templateCache = new FileTemplateCache(templateDir);
\r
93 templateCache.setLoadingPolicy(FileTemplateCache.LOAD_ON_DEMAND);
\r
94 // gone in freemarker 1.7.1: templateCache.startAutoUpdate();
\r
97 docRoot = configuration.getString("RootUri");
\r
99 actionRoot = docRoot +configuration.getString("Producer.ActionServlet");
\r
101 catch (ConfigException ce) {
\r
102 // if Producer.ActionServlet is not set in the conf file
\r
103 actionRoot = docRoot + "/Mir";
\r
108 * empty private constructor, to avoid instantiation
\r
110 private HTMLTemplateProcessor() {
\r
114 * Wandelt Liste mit Entities <code>entList</code> in freemarker-Struktur um, mischt die Daten mit
\r
115 * Template <code>templateFilename</code> und gibt das Ergebnis an den PrintWriter
\r
118 * @param templateFilename
\r
121 * @exception HTMLParseException
\r
124 public static void process(HttpServletResponse res, String templateFilename, EntityList entList, PrintWriter out, Locale locale, Locale aFallbackLocale) throws HTMLParseException {
\r
125 process(res, templateFilename, entList, (String)null, (TemplateModelRoot) null, out, locale, aFallbackLocale);
\r
129 * Wandelt Entitylist in freemarker-Struktur um, f?gt <code>additionalModel</code>
\r
130 * unter dem Namen <code>additionalModelName</code> ein und mischt die Daten mit
\r
131 * Template <code>templateFilename</code> und gibt das Ergebnis an den PrintWriter
\r
134 * @param templateFilename
\r
136 * @param additionalModelName
\r
137 * @param additionalModel
\r
139 * @exception HTMLParseException
\r
142 public static void process(HttpServletResponse res, String templateFilename,
\r
143 EntityList entList, String additionalModelName,
\r
144 TemplateModelRoot additionalModel, PrintWriter out,
\r
145 Locale locale, Locale aFallbackLocale) throws HTMLParseException {
\r
147 SimpleHash modelRoot = new SimpleHash();
\r
149 if (entList == null) {
\r
150 process(null, templateFilename, modelRoot, null, out, locale, aFallbackLocale);
\r
154 modelRoot = makeSimpleHashWithEntitylistInfos(entList);
\r
156 // Quickhack um mal ein Popup mit reinzunhemen ..
\r
157 if (additionalModelName != null && additionalModel != null)
\r
158 modelRoot.put(additionalModelName, additionalModel);
\r
160 process(res, templateFilename, modelRoot, null, out, locale, aFallbackLocale);
\r
162 catch (StorageObjectFailure e) {
\r
163 throw new HTMLParseException(e.toString());
\r
170 * Mischt die freemarker-Struktur <code>tmr</code> mit
\r
171 * Template <code>templateFilename</code> und gibt das Ergebnis an den PrintWriter
\r
174 * @param templateFilename
\r
177 * @exception HTMLParseException
\r
179 public static void process(HttpServletResponse res, String templateFilename,
\r
180 TemplateModelRoot tmr, PrintWriter out,
\r
181 Locale locale, Locale aFallbackLocale) throws HTMLParseException {
\r
182 process(res, templateFilename, tmr, null, out, locale, aFallbackLocale);
\r
186 * Mischt die freemarker-Struktur <code>tmr</code> mit
\r
187 * Template <code>templateFilename</code> und gibt das Ergebnis an den PrintWriter
\r
190 * @param templateFilename
\r
193 * @exception HTMLParseException
\r
195 public static void process(HttpServletResponse res, String templateFilename,
\r
196 TemplateModelRoot tmr, TemplateModelRoot extra,
\r
197 PrintWriter out, Locale locale, Locale aFallbackLocale) throws HTMLParseException {
\r
200 throw new HTMLParseException("no outputstream");
\r
201 Template tmpl = getTemplateFor(templateFilename);
\r
203 throw new HTMLParseException("no template: " + templateFilename);
\r
205 tmr = new SimpleHash();
\r
207 /** @todo what is this for? (rk) */
\r
208 String session = "";
\r
210 session = res.encodeURL("");
\r
213 SimpleHash configHash = new SimpleHash();
\r
215 // pass the whole config hash to the templates
\r
216 Iterator it = configuration.getKeys();
\r
218 while (it.hasNext()) {
\r
219 key = (String) it.next();
\r
220 configHash.put(key, new SimpleScalar(
\r
221 configuration.getString(key))
\r
225 // this does not come directly from the config file
\r
226 configHash.put("docRoot", new SimpleScalar(docRoot));
\r
227 configHash.put("actionRoot", new SimpleScalar(actionRoot + session));
\r
228 configHash.put("now",
\r
229 new SimpleScalar(StringUtil.date2readableDateTime(new GregorianCalendar())));
\r
231 // this conform to updated freemarker syntax
\r
232 configHash.put("compressWhitespace",
\r
233 new freemarker.template.utility.CompressWhitespace());
\r
235 SimpleHash utilityHash = new SimpleHash();
\r
237 utilityHash.put("compressWhitespace",
\r
238 new freemarker.template.utility.CompressWhitespace());
\r
239 utilityHash.put("encodeURI",
\r
240 FreemarkerGenerator.makeAdapter(new GeneratorHTMLFunctions.
\r
241 encodeURIGeneratorFunction()));
\r
242 utilityHash.put("encodeHTML",
\r
243 FreemarkerGenerator.makeAdapter(new GeneratorHTMLFunctions.
\r
244 encodeHTMLGeneratorFunction()));
\r
245 utilityHash.put("isOdd",
\r
246 FreemarkerGenerator.makeAdapter(new GeneratorIntegerFunctions.
\r
248 utilityHash.put("increment",
\r
249 FreemarkerGenerator.makeAdapter(new GeneratorIntegerFunctions.
\r
250 incrementFunction()));
\r
252 catch (Throwable t) {
\r
253 throw new HTMLParseException(t.getMessage());
\r
256 SimpleHash outPutHash = new SimpleHash();
\r
258 if (extra != null) {
\r
259 outPutHash.put("extra", extra);
\r
261 outPutHash.put("data", tmr);
\r
262 outPutHash.put("config", configHash);
\r
263 outPutHash.put("utility", utilityHash);
\r
265 MessageResources messages[] = new MessageResources[bundles.length];
\r
267 for (int i=0; i<bundles.length; i++) {
\r
268 messages[i] = MessageResources.getMessageResources(bundles[i]);
\r
272 outPutHash.put("lang", FreemarkerGenerator.makeAdapter(new ResourceBundleGeneratorFunction(new Locale[] {locale, aFallbackLocale}, messages)));
\r
274 catch (Throwable t) {
\r
275 throw new HTMLParseException(t.toString());
\r
278 tmpl.process(outPutHash, out);
\r
282 * Converts Entity-List to SimpleList of SimpleHashes.
\r
283 * @param aList ist eine Liste von Entity
\r
284 * @return eine freemarker.template.SimpleList von SimpleHashes.
\r
286 * @deprecated EntityLists comply with TemplateListModel now.
\r
288 public static SimpleList makeSimpleList(EntityList aList) throws StorageObjectFailure {
\r
289 logger.warn("using deprecated makeSimpleList(entityList) - a waste of resources");
\r
290 SimpleList simpleList = new SimpleList();
\r
291 if (aList != null) {
\r
292 for (int i = 0; i < aList.size(); i++) {
\r
293 simpleList.add(aList.elementAt(i));
\r
300 * Konvertiert ein EntityList in ein freemarker.template.SimpleHash-Modell. Im Hash
\r
301 * sind die einzelnen Entities ueber ihre id zu erreichen.
\r
302 * @param aList ist die EntityList
\r
303 * @return SimpleHash mit den entsprechenden freemarker Daten
\r
306 public static SimpleHash makeSimpleHash(EntityList aList) throws
\r
307 StorageObjectFailure {
\r
308 SimpleHash simpleHash = new SimpleHash();
\r
309 Entity currentEntity;
\r
311 if (aList != null) {
\r
312 for (int i = 0; i < aList.size(); i++) {
\r
313 currentEntity = (Entity) aList.elementAt(i);
\r
314 simpleHash.put(currentEntity.getId(), currentEntity);
\r
321 * Konvertiert ein Hashtable mit den keys und values als String
\r
322 * in ein freemarker.template.SimpleHash-Modell
\r
323 * @param mergeData der Map mit den String / String Daten
\r
324 * @return SimpleHash mit den entsprechenden freemarker Daten
\r
327 public static SimpleHash makeSimpleHash(Map mergeData) {
\r
328 SimpleHash modelRoot = new SimpleHash();
\r
330 if (mergeData != null) {
\r
331 Set set = mergeData.keySet();
\r
332 Iterator it = set.iterator();
\r
333 for (int i = 0; i < set.size(); i++) {
\r
334 aField = (String) it.next();
\r
335 modelRoot.put(aField, (String) mergeData.get(aField));
\r
342 * Converts EntityList in SimpleHash and adds additional information
\r
343 * to the returned SimpleHash
\r
346 * @return SimpleHash returns SimpleHash with the converted EntityList plus
\r
347 * additional Data about the list.
\r
348 * @exception StorageObjectException
\r
351 public static SimpleHash makeSimpleHashWithEntitylistInfos(EntityList entList) throws
\r
352 StorageObjectFailure {
\r
353 SimpleHash modelRoot = new SimpleHash();
\r
354 if (entList != null) {
\r
355 modelRoot.put("contentlist", entList);
\r
356 modelRoot.put("count",
\r
357 new SimpleScalar( (new Integer(entList.getCount())).toString()));
\r
358 if (entList.getWhere() != null) {
\r
359 modelRoot.put("where", new SimpleScalar(entList.getWhere()));
\r
360 modelRoot.put("where_encoded",
\r
361 new SimpleScalar(URLEncoder.encode(entList.getWhere())));
\r
363 if (entList.getOrder() != null) {
\r
364 modelRoot.put("order", new SimpleScalar(entList.getOrder()));
\r
365 modelRoot.put("order_encoded",
\r
366 new SimpleScalar(URLEncoder.encode(entList.getOrder())));
\r
368 modelRoot.put("from",
\r
369 new SimpleScalar( (new Integer(entList.getFrom())).toString()));
\r
370 modelRoot.put("to",
\r
371 new SimpleScalar( (new Integer(entList.getTo())).toString()));
\r
373 if (entList.hasNextBatch())
\r
374 modelRoot.put("next",
\r
375 new SimpleScalar( (new Integer(entList.getNextBatch())).
\r
377 if (entList.hasPrevBatch())
\r
378 modelRoot.put("prev",
\r
379 new SimpleScalar( (new Integer(entList.getPrevBatch())).
\r
386 * Private methods to get template from a templateFilename
\r
387 * @param templateFilename
\r
389 * @exception HTMLParseException
\r
391 private static Template getTemplateFor(String templateFilename) throws
\r
392 HTMLParseException {
\r
393 Template returnTemplate = null;
\r
394 if (templateFilename != null)
\r
395 returnTemplate = (Template) templateCache.getItem(templateFilename,
\r
398 if (returnTemplate == null) {
\r
399 logger.error("CACHE (ERR): Unknown template: " + templateFilename);
\r
400 throw new HTMLParseException("Templatefile: " + templateFilename + " not found.");
\r
403 return returnTemplate;
\r