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