1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package de.fu_berlin.ties.util;
23
24 import java.io.File;
25 import java.io.FileWriter;
26 import java.io.IOException;
27 import java.io.OutputStreamWriter;
28 import java.io.Writer;
29 import java.util.ArrayList;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Properties;
35 import java.util.SortedSet;
36
37 import org.apache.commons.lang.StringEscapeUtils;
38 import org.apache.velocity.VelocityContext;
39 import org.apache.velocity.app.Velocity;
40 import org.apache.velocity.context.Context;
41 import org.apache.velocity.exception.VelocityException;
42 import org.apache.velocity.runtime.RuntimeConstants;
43
44 import de.fu_berlin.ties.TiesConfiguration;
45 import de.fu_berlin.ties.io.IOUtils;
46
47 /***
48 * A static class that provides a convenience interface to a Velocity
49 * singletons. No instances of this class can be created, only the static
50 * members should be used.
51 *
52 * @author Christian Siefkes
53 * @version $Revision: 1.17 $, $Date: 2004/11/08 11:57:48 $, $Author: siefkes $
54 */
55 public final class VelocityService {
56
57 /***
58 * The changes to the Velocity configuration made by default.
59 */
60 private static final Properties DEFAULT_PROPERTIES;
61
62 /***
63 * The template directory.
64 */
65 public static final String TEMPLATE_DIR = "velocity" + File.separator;
66
67 /***
68 * The extension of template files.
69 */
70 public static final String TEMPLATE_EXT = ".vm";
71
72 /***
73 * Name of the default template used to print configuration parameters.
74 */
75 public static final String CONFIG_TEMPLATE = completeTemplateName("config");
76
77 /***
78 * Name of the default template used to print goals.
79 */
80 public static final String GOAL_TEMPLATE = completeTemplateName("goals");
81
82 /***
83 * Name of the main template used for Anakia XML format.
84 */
85 public static final String ANAKIA_TEMPLATE = completeTemplateName("xdoc");
86
87 /***
88 * Static initializer populates the default properties and configures the
89 * Velocity singleton.
90 */
91 static {
92
93 DEFAULT_PROPERTIES = new Properties();
94
95 DEFAULT_PROPERTIES.setProperty(
96 RuntimeConstants.RESOURCE_LOADER, "file,classpath");
97
98 DEFAULT_PROPERTIES.setProperty(
99 RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, "true");
100 DEFAULT_PROPERTIES.setProperty(
101 "file.resource.loader.modificationCheckInterval", "120");
102
103 DEFAULT_PROPERTIES.setProperty("classpath.resource.loader.class",
104 "org.apache.velocity.runtime.resource.loader."
105 + "ClasspathResourceLoader");
106 DEFAULT_PROPERTIES.setProperty("classpath.resource.loader.description",
107 "Velocity Classpath Resource Loader");
108
109 try {
110
111
112
113
114
115
116
117
118
119 Velocity.init(DEFAULT_PROPERTIES);
120 } catch (Exception e) {
121 Util.LOG.error(
122 "VelocityService: could not initialize the Velocity singleton",
123 e);
124 }
125 }
126
127 /***
128 * Completes the short form of a template name, by prepending the
129 * {@link #TEMPLATE_DIR} and appending the {@link #TEMPLATE_EXT}.
130 *
131 * @param shortName the short form of the template name (without directory
132 * and extension)
133 * @return the full form of the template name, which is assumed to be
134 * in the default directory and have the default extension
135 */
136 public static String completeTemplateName(final String shortName) {
137 return TEMPLATE_DIR + shortName + TEMPLATE_EXT;
138 }
139
140 /***
141 * Returns properties listing the changes to the Velocity configuration
142 * made by default.
143 *
144 * @return a {@link java.util.Properties} object containing the changed
145 * parameters
146 */
147 public static Properties getDefaultProperties() {
148 return DEFAULT_PROPERTIES;
149 }
150
151 /***
152 * Main methods: prints the list of config parameters and
153 * {@linkplain #printGoals(TiesConfiguration, Writer) goals} from the
154 * {@link TiesConfiguration#CONF standard configuration} to specified
155 * files (or standard out). The generated files are in Anakia XML format
156 * and uses the platform's default character set.
157 *
158 * @param args the command-line arguments: should contain the filename
159 * for writing the config parameters as first element and the filename
160 * for writing the goals as second element; if no filenames are given, the
161 * corresponding output is written to standard out
162 */
163 public static void main(final String[] args) {
164 Writer confWriter = null;
165 Writer goalWriter = null;
166
167 try {
168
169 confWriter = (args.length > 0)
170 ? new FileWriter(args[0])
171 : new OutputStreamWriter(System.out);
172 final Map<String, Object> confContextObjects =
173 new HashMap<String, Object>();
174 confContextObjects.put("contents", CONFIG_TEMPLATE);
175 confContextObjects.put("title", "TIE Configuration Parameters");
176 confContextObjects.put("keywords", "TIE, configuration, "
177 + "configuration parameters, properties, default values");
178 printConfigProperties(TiesConfiguration.CONF, ANAKIA_TEMPLATE,
179 IOUtils.STANDARD_UNICODE_CHARSET, confContextObjects,
180 confWriter);
181
182
183 goalWriter = (args.length > 1)
184 ? new FileWriter(args[1])
185 : new OutputStreamWriter(System.out);
186 final Map<String, Object> goalContextObjects =
187 new HashMap<String, Object>();
188 goalContextObjects.put("contents", GOAL_TEMPLATE);
189 goalContextObjects.put("title", "TIE Processing Goals");
190 goalContextObjects.put("keywords", "TIE, goals, "
191 + "processors, processing goals, goal processors");
192 printGoals(TiesConfiguration.CONF, ANAKIA_TEMPLATE,
193 IOUtils.STANDARD_UNICODE_CHARSET, goalContextObjects,
194 goalWriter);
195 } catch (Exception e) {
196 e.printStackTrace();
197 } finally {
198
199 IOUtils.tryToClose(confWriter);
200 IOUtils.tryToClose(goalWriter);
201 }
202 }
203
204 /***
205 * Prints all properties contained in a configuration, using the
206 * specified template for rendering. In addition to the user-specified
207 * context objects (if any), the template has access to a collection
208 * <code>$allParameters</code> of all config parameters.
209 *
210 * @param config the configuration to print
211 * @param templateName name of template to be used in merge, either in
212 * short form (without directory and extension, when default directory and
213 * extension are used) or in complete form
214 * @param charset the character set used in the template
215 * @param contextObjects a map of objects that are made available in the
216 * context of the template; might be <code>null</code>
217 * @param writer the writer to write the output to; the writer is flushed
218 * but not closed by this method
219 * @throws IOException if an I/O error occurred
220 * @throws VelocityException if rendering failed
221 */
222 public static void printConfigProperties(final TiesConfiguration config,
223 final String templateName, final String charset,
224 final Map<String, Object> contextObjects, final Writer writer)
225 throws IOException, VelocityException {
226
227 final Map<String, Object> contextMap = (contextObjects == null)
228 ? new HashMap<String, Object>()
229 : new HashMap<String, Object>(contextObjects);
230
231
232 final SortedSet keySet = config.sortedKeys(true);
233 final Iterator keys = keySet.iterator();
234 final List<TiesConfiguration.EntryDescriptor> allParams =
235 new ArrayList<TiesConfiguration.EntryDescriptor>(keySet.size());
236 String key;
237 TiesConfiguration.EntryDescriptor descriptor;
238
239 while (keys.hasNext()) {
240 key = (String) keys.next();
241 descriptor = config.getDescriptor(key);
242
243 if (descriptor != null) {
244 allParams.add(descriptor);
245 } else {
246 Util.LOG.warn("Missing description for key " + key);
247 }
248 }
249
250 contextMap.put("allParameters", allParams);
251 VelocityService.renderTemplate(templateName, charset, contextMap,
252 writer);
253 }
254
255 /***
256 * Prints all properties contained in a configuration, using the
257 * default template for printing them. This templates generates an
258 * (X)HTML fragment listing all configuration parameters with their
259 * types and default values in a table.
260 *
261 * @param config the configuration to print
262 * @param writer the writer to write the output to; the writer is flushed
263 * but not closed by this method
264 * @throws IOException if an I/O error occurred
265 * @throws VelocityException if rendering failed
266 */
267 public static void printConfigProperties(final TiesConfiguration config,
268 final Writer writer) throws IOException, VelocityException {
269 printConfigProperties(config, CONFIG_TEMPLATE,
270 IOUtils.STANDARD_UNICODE_CHARSET, null, writer);
271 }
272
273 /***
274 * Prints the goals contained in a configuration, using the default
275 * template for printing them. In addition to the user-specified
276 * context objects (if any), the template has access to a collection
277 * <code>$allParameters</code> of all goals.
278 *
279 * @param config the configuration to print
280 * @param templateName name of template to be used in merge, either in
281 * short form (without directory and extension, when default directory and
282 * extension are used) or in complete form
283 * @param charset the character set used in the template
284 * @param contextObjects a map of objects that are made available in the
285 * context of the template; might be <code>null</code>
286 * @param writer the writer to write the output to; the writer is flushed
287 * but not closed by this method
288 * @throws IOException if an I/O error occurred
289 * @throws VelocityException if rendering failed
290 */
291 public static void printGoals(final TiesConfiguration config,
292 final String templateName, final String charset,
293 final Map<String, Object> contextObjects, final Writer writer)
294 throws IOException, VelocityException {
295 final TiesConfiguration goalSubset = (TiesConfiguration)
296 config.subset(TiesConfiguration.CONFIG_GOAL_PREFIX);
297 printConfigProperties(goalSubset, templateName,
298 charset, contextObjects, writer);
299 }
300
301 /***
302 * Prints the goals contained in a configuration, using the default
303 * template for printing them. This templates generates an (X)HTML fragment
304 * listing all goals with their output extension (if given) and any further
305 * arguments in a table.
306 *
307 * @param config the configuration to print
308 * @param writer the writer to write the output to; the writer is flushed
309 * but not closed by this method
310 * @throws IOException if an I/O error occurred
311 * @throws VelocityException if rendering failed
312 */
313 public static void printGoals(final TiesConfiguration config,
314 final Writer writer) throws IOException, VelocityException {
315 printGoals(config, GOAL_TEMPLATE, IOUtils.STANDARD_UNICODE_CHARSET,
316 null, writer);
317 }
318
319 /***
320 * Renders a template using the given context objects. The template must
321 * be in the standard Unicode character set (UFT-8).
322 *
323 * @param templateName name of template to be used in merge, either in
324 * short form (without directory and extension, when default directory and
325 * extension are used) or in complete form
326 * @param contextObjects a map of objects that are made available in the
327 * context of the template; mappings from "escapeTool" to a
328 * {@link StringEscapeUtils} and from "util" to a {@link Util} are added to
329 * allow XML entity escaping, String conversion etc.
330 * @param writer writer to write template into; the writer is flushed
331 * but not closed by this method
332 * @throws IOException if an I/O error occurred
333 * @throws VelocityException if rendering failed
334 */
335 public static void renderTemplate(final String templateName,
336 final Map contextObjects, final Writer writer)
337 throws IOException, VelocityException {
338 renderTemplate(templateName, IOUtils.STANDARD_UNICODE_CHARSET,
339 contextObjects, writer);
340 }
341
342 /***
343 * Renders a template using the given context objects.
344 *
345 * @param templateName name of template to be used in merge, either in
346 * short form (without directory and extension, when default directory and
347 * extension are used) or in complete form
348 * @param charset the character set used in template
349 * @param contextObjects a map of objects that are made available in the
350 * context of the template; mappings from "escapeTool" to a
351 * {@link StringEscapeUtils} and from "util" to a {@link Util} are added to
352 * allow XML entity escaping, String conversion etc.
353 * @param writer writer to write template into; the writer is flushed
354 * but not closed by this method
355 * @throws IOException if an I/O error occurred
356 * @throws VelocityException if rendering failed
357 */
358 public static void renderTemplate(final String templateName,
359 final String charset, final Map contextObjects, final Writer writer)
360 throws IOException, VelocityException {
361 final Context context = new VelocityContext(contextObjects);
362
363
364 final String embeddedTemplateName = completeTemplateName(templateName);
365
366
367 final String actualTemplateName =
368 Velocity.resourceExists(embeddedTemplateName)
369 ? embeddedTemplateName : templateName;
370
371
372 context.put("escapeTool", new StringEscapeUtils());
373 context.put("util", new Util());
374 boolean result = false;
375
376 try {
377 result = Velocity.mergeTemplate(actualTemplateName, charset,
378 context, writer);
379 writer.flush();
380 } catch (IOException ioe) {
381 throw ioe;
382 } catch (VelocityException ve) {
383 throw ve;
384 } catch (RuntimeException re) {
385 throw re;
386 } catch (Exception e) {
387
388 final VelocityException ve = new VelocityException(
389 "Exception during rendering: " + e.toString());
390 ve.initCause(e);
391 throw ve;
392 }
393
394
395 if (!result) {
396 throw new VelocityException("Velocity could not render the template"
397 + "-- check log for errors");
398 }
399 }
400
401 /***
402 * Private constructor prevents creation of instances.
403 */
404 private VelocityService() {
405 super();
406 }
407 }