2 * Copyright (C) 2001, 2002 The Mir-coders group
4 * This file is part of Mir.
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.
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.
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
20 * In addition, as a special exception, The Mir-coders gives permission to link
21 * the code of this program with any library licensed under the Apache Software License,
22 * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23 * (or with modified versions of the above that use the same license as the above),
24 * and distribute linked combinations including the two. You must obey the
25 * GNU General Public License in all respects for all of the code used other than
26 * the above mentioned libraries. If you modify this file, you may extend this
27 * exception to your version of the file, but you are not obligated to do so.
28 * If you do not wish to do so, delete this exception statement from your version.
30 package mir.generator;
32 import java.io.PrintWriter;
33 import java.io.StringWriter;
34 import java.util.AbstractList;
35 import java.util.Date;
36 import java.util.HashMap;
37 import java.util.Iterator;
38 import java.util.List;
40 import java.util.Vector;
42 import org.apache.commons.beanutils.MethodUtils;
43 import org.apache.commons.beanutils.PropertyUtils;
44 import org.apache.velocity.Template;
45 import org.apache.velocity.VelocityContext;
46 import org.apache.velocity.app.VelocityEngine;
47 import org.apache.velocity.context.Context;
48 import org.apache.velocity.exception.ParseErrorException;
49 import org.apache.velocity.exception.ResourceNotFoundException;
50 import org.apache.velocity.runtime.RuntimeServices;
51 import org.apache.velocity.runtime.log.LogSystem;
52 import mir.log.LoggerWrapper;
53 import mir.util.GeneratorFormatAdapters;
54 import mir.util.RewindableIterator;
56 public class VelocityGenerator implements Generator {
57 private String templateIdentifier;
58 private VelocityGeneratorLibrary library;
59 private static LoggerWrapper logger = new LoggerWrapper("Generator.velocity");
67 public VelocityGenerator(String aTemplate, VelocityGeneratorLibrary aLibrary) {
68 templateIdentifier = aTemplate;
74 * @param anOutputWriter
77 * @throws GeneratorExc
78 * @throws GeneratorFailure
80 public void generate(Object anOutputWriter, Map aValues, LoggerWrapper aLogger) throws GeneratorExc, GeneratorFailure {
82 Context context = makeMapAdapter(aValues);
83 StringWriter stringWriter = new StringWriter();
86 template = library.engine.getTemplate(templateIdentifier);
87 if (template == null) {
88 throw new GeneratorExc("VelocityGeneratorLibrary: Can't find template " + templateIdentifier);
90 template.merge(context, stringWriter);
92 ( (PrintWriter) anOutputWriter).print(stringWriter.toString());
94 catch (ResourceNotFoundException t) {
95 throw new GeneratorExc("VelocityGeneratorLibrary: Can't find template " + templateIdentifier);
97 catch (ParseErrorException t) {
98 ( (PrintWriter) anOutputWriter).print(t.toString());
100 catch (Throwable t) {
101 throw new GeneratorFailure(t);
109 * <p>Description: </p>
110 * <p>Copyright: Copyright (c) 2003</p>
112 * @author not attributable
115 private static class ContextAdapter implements Context {
116 public boolean containsKey(java.lang.Object key) {
120 public Object get(java.lang.String key) {
124 public Object[] getKeys() {
125 return new Object[] {};
128 public Object put(java.lang.String key, java.lang.Object value) {
132 public Object remove(java.lang.Object key) {
142 private static Context makeMapAdapter(Map aMap) {
143 return new MapAdapter(aMap);
151 private static List makeIteratorAdapter(Iterator anIterator) {
152 return new IteratorAdapter(anIterator);
160 private static List makeListAdapter(List aList) {
161 return new ListAdapter(aList);
169 private static Object makeFunctionAdapter(Generator.GeneratorFunction aFunction) {
170 return new FunctionAdapter(aFunction);
178 private static Object makeBeanAdapter(Object anObject) {
179 return new BeanAdapter(anObject);
185 * <p>Description: </p>
186 * <p>Copyright: Copyright (c) 2003</p>
188 * @author not attributable
191 private interface VelocityAdapter {
192 public Object getOriginal();
200 public static Object unmakeAdapter(Object anObject) {
201 if (anObject instanceof VelocityAdapter) {
202 return ((VelocityAdapter) anObject).getOriginal();
213 public static Object makeAdapter(Object anObject) {
214 if (anObject == null)
217 if (anObject instanceof Context)
220 else if (anObject instanceof Generator.GeneratorFunction)
221 return makeFunctionAdapter((Generator.GeneratorFunction) anObject);
222 else if (anObject instanceof Integer)
224 else if (anObject instanceof Boolean)
226 else if (anObject instanceof String)
228 else if (anObject instanceof Map)
229 return makeMapAdapter((Map) anObject);
230 else if (anObject instanceof Iterator)
231 return makeIteratorAdapter((Iterator) anObject);
232 else if (anObject instanceof List)
233 return makeListAdapter(((List) anObject));
234 else if (anObject instanceof Number)
235 return makeAdapter(new GeneratorFormatAdapters.NumberFormatAdapter((Number) anObject));
236 else if (anObject instanceof Date)
237 return makeAdapter(new GeneratorFormatAdapters.DateFormatAdapter((Date) anObject));
239 return makeBeanAdapter(anObject);
245 * <p>Description: </p>
246 * <p>Copyright: Copyright (c) 2003</p>
248 * @author not attributable
251 public static class FunctionAdapter implements VelocityAdapter {
252 private GeneratorFunction function;
254 public Object getOriginal() {
258 private FunctionAdapter(GeneratorFunction aFunction) {
259 function = aFunction;
262 public Object call(Object aParameters[]) throws GeneratorExc {
263 List parameters = new Vector();
265 for (int i = 0; i<aParameters.length; i++) {
266 parameters.add(unmakeAdapter(aParameters[i]));
269 return makeAdapter(function.perform(parameters));
272 public Object call() throws GeneratorExc {
273 return makeAdapter(function.perform(new Vector()));
276 public Object call(Object anObject) throws GeneratorExc {
277 return call(new Object[] { anObject });
280 public Object call(Object anObject1, Object anObject2) throws GeneratorExc {
281 return call(new Object[] { anObject1, anObject2 });
284 public Object call(Object anObject1, Object anObject2, Object anObject3) throws GeneratorExc {
285 return call(new Object[] { anObject1, anObject2, anObject3 });
288 public Object call(Object anObject1, Object anObject2, Object anObject3, Object anObject4) throws GeneratorExc {
289 return call(new Object[] { anObject1, anObject2, anObject3, anObject4 });
297 * <p>Description: </p>
298 * <p>Copyright: Copyright (c) 2003</p>
300 * @author not attributable
303 private static class MapAdapter implements Context, VelocityAdapter {
305 private Map valuesCache;
307 private MapAdapter(Map aMap) {
309 valuesCache = new HashMap();
312 public Object getOriginal() {
316 public boolean containsKey(Object aKey) {
317 return map.containsKey(aKey);
320 public Object get(String aKey) {
322 if (!valuesCache.containsKey(aKey)) {
323 Object value = map.get(aKey);
325 if (value == null && !map.containsKey(aKey)) {
326 return "no key "+aKey+" available";
329 valuesCache.put(aKey, makeAdapter(value));
332 return valuesCache.get(aKey);
334 catch (Throwable t) {
335 throw new GeneratorFailure(t);
339 public Object[] getKeys() {
340 return new Object[] {};
343 public Object put(String aKey, Object aValue) {
344 valuesCache.remove(aKey);
345 map.put(aKey, unmakeAdapter(aValue));
350 public Object remove(java.lang.Object key) {
358 * <p>Description: </p>
359 * <p>Copyright: Copyright (c) 2003</p>
361 * @author not attributable
364 private static class IteratorAdapter extends AbstractList implements VelocityAdapter {
365 private Iterator iterator;
366 private List valuesCache;
367 private int position;
369 private IteratorAdapter(Iterator anIterator) {
370 iterator = anIterator;
372 valuesCache = new Vector();
376 if (iterator instanceof RewindableIterator) {
377 ((RewindableIterator) iterator).rewind();
381 private void getUntil(int anIndex) {
382 while ((anIndex==-1 || valuesCache.size()<=anIndex) && iterator.hasNext())
384 valuesCache.add(makeAdapter(iterator.next()));
388 public Object getOriginal() {
392 public Object get(int anIndex) {
397 if (anIndex<valuesCache.size())
399 result = valuesCache.get(anIndex);
404 throw new RuntimeException( "Iterator out of bounds" );
409 return valuesCache.size();
417 * <p>Description: </p>
418 * <p>Copyright: Copyright (c) 2003</p>
420 * @author not attributable
423 private static class ListAdapter extends AbstractList implements VelocityAdapter {
425 private List valuesCache;
426 private int position;
428 private ListAdapter(List aList) {
431 valuesCache = new Vector();
435 private void getUntil(int anIndex) {
436 while ((anIndex==-1 || valuesCache.size()<=anIndex) && valuesCache.size()<list.size())
438 valuesCache.add(makeAdapter(list.get(valuesCache.size())));
442 public Object getOriginal() {
446 public Object get(int anIndex) {
451 if (anIndex<valuesCache.size())
453 result = valuesCache.get(anIndex);
458 throw new RuntimeException( "Iterator out of bounds" );
470 * <p>Description: </p>
471 * <p>Copyright: Copyright (c) 2003</p>
473 * @author not attributable
476 private static class BeanAdapter implements Context, VelocityAdapter {
477 private Object object;
479 public BeanAdapter(Object anObject) {
483 public boolean containsKey(Object key) {
487 public Object getOriginal() {
491 public Object get(String aKey) {
493 if (PropertyUtils.isReadable(object, aKey))
494 return makeAdapter(PropertyUtils.getSimpleProperty(object, aKey));
496 return makeAdapter(MethodUtils.invokeExactMethod(object, "get", aKey));
498 catch (Throwable t) {
499 throw new GeneratorFailure(t);
503 public Object[] getKeys() {
504 return new Object[] {};
507 public Object put(String aKey, Object aValue) {
509 if (PropertyUtils.isWriteable(object, aKey))
510 PropertyUtils.setSimpleProperty(object, aKey, unmakeAdapter(aValue));
512 MethodUtils.invokeExactMethod(object, "set", new Object[] {aKey, unmakeAdapter(aValue)});
516 catch (Throwable t) {
517 throw new GeneratorFailure(t);
521 public Object remove(Object aKey) {
522 throw new RuntimeException("BeanAdapter.remove not supported");
529 * <p>Description: </p>
530 * <p>Copyright: Copyright (c) 2003</p>
532 * @author not attributable
535 private static class VelocityLoggerWrapper implements LogSystem {
536 private LoggerWrapper logger;
538 public VelocityLoggerWrapper(LoggerWrapper aLogger) {
542 public void init(RuntimeServices aRuntimeServices) {
545 public void logVelocityMessage(int aLevel, String aMessage) {
548 logger.debug(aMessage);
551 logger.error(aMessage);
554 logger.info(aMessage);
557 logger.warn(aMessage);
566 * <p>Description: </p>
567 * <p>Copyright: Copyright (c) 2003</p>
569 * @author not attributable
572 public static class VelocityGeneratorLibrary implements GeneratorLibrary {
573 private VelocityEngine engine;
575 public VelocityGeneratorLibrary(String aTemplateRoot) throws GeneratorExc, GeneratorFailure {
577 engine = new VelocityEngine();
579 engine.setProperty(VelocityEngine.RESOURCE_LOADER, "file");
581 catch (Throwable t) {
582 logger.error(VelocityEngine.RESOURCE_LOADER);
586 engine.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
588 catch (Throwable t) {
589 logger.error("file.resource.loader.class");
593 engine.setProperty("file.resource.loader.path", aTemplateRoot);
595 catch (Throwable t) {
596 logger.error("file.resource.loader.path");
600 engine.setProperty("file.resource.loader.cache", "true");
602 catch (Throwable t) {
603 logger.error("file.resource.loader.cache");
607 engine.setProperty("file.resource.loader.modificationCheckInterval", "10");
609 catch (Throwable t) {
610 logger.error("file.resource.loader.modificationCheckInterval");
615 engine.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM, new VelocityLoggerWrapper(logger));
617 catch (Throwable t) {
618 logger.error(VelocityEngine.RUNTIME_LOG_LOGSYSTEM);
623 catch (Throwable t) {
624 t.printStackTrace(logger.asPrintWriter(logger.ERROR_MESSAGE));
626 logger.error("Failed to set up a VelocityGeneratorLibrary: " + t.toString());
627 throw new GeneratorFailure(t);
631 public Generator makeGenerator(String anIdentifier) throws GeneratorExc, GeneratorFailure {
632 return new VelocityGenerator(anIdentifier, this);
639 * <p>Description: </p>
640 * <p>Copyright: Copyright (c) 2003</p>
642 * @author not attributable
645 public static class VelocityGeneratorLibraryFactory implements GeneratorLibraryFactory {
646 private String basePath;
648 public VelocityGeneratorLibraryFactory(String aBasePath) {
649 basePath = aBasePath;
652 public GeneratorLibrary makeLibrary(String anInitializationString) throws GeneratorExc, GeneratorFailure {
653 return new VelocityGeneratorLibrary(basePath+anInitializationString);