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;
35 import java.util.AbstractList;
36 import java.util.Date;
37 import java.util.HashMap;
38 import java.util.Iterator;
39 import java.util.List;
41 import java.util.Vector;
43 import org.apache.commons.beanutils.MethodUtils;
44 import org.apache.commons.beanutils.PropertyUtils;
45 import org.apache.velocity.Template;
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);
111 private static Context makeMapAdapter(Map aMap) {
112 return new MapAdapter(aMap);
120 private static List makeIteratorAdapter(Iterator anIterator) {
121 return new IteratorAdapter(anIterator);
129 private static List makeListAdapter(List aList) {
130 return new ListAdapter(aList);
138 private static Object makeFunctionAdapter(Generator.Function aFunction) {
139 return new FunctionAdapter(aFunction);
147 private static Object makeBeanAdapter(Object anObject) {
148 return new BeanAdapter(anObject);
154 * <p>Description: </p>
155 * <p>Copyright: Copyright (c) 2003</p>
157 * @author not attributable
160 private interface VelocityAdapter {
161 public Object getOriginal();
169 public static Object unmakeAdapter(Object anObject) {
170 if (anObject instanceof VelocityAdapter) {
171 return ((VelocityAdapter) anObject).getOriginal();
182 public static Object makeAdapter(Object anObject) {
183 if (anObject == null)
186 if (anObject instanceof Context)
189 else if (anObject instanceof Generator.Function)
190 return makeFunctionAdapter((Generator.Function) anObject);
191 else if (anObject instanceof Integer)
193 else if (anObject instanceof Boolean)
195 else if (anObject instanceof String)
197 else if (anObject instanceof Map)
198 return makeMapAdapter((Map) anObject);
199 else if (anObject instanceof Iterator)
200 return makeIteratorAdapter((Iterator) anObject);
201 else if (anObject instanceof List)
202 return makeListAdapter(((List) anObject));
203 else if (anObject instanceof Number)
204 return makeAdapter(new GeneratorFormatAdapters.NumberFormatAdapter((Number) anObject));
205 else if (anObject instanceof Date)
206 return makeAdapter(new GeneratorFormatAdapters.DateFormatAdapter((Date) anObject));
208 return makeBeanAdapter(anObject);
214 * <p>Description: </p>
215 * <p>Copyright: Copyright (c) 2003</p>
217 * @author not attributable
220 public static class FunctionAdapter implements VelocityAdapter {
221 private Function function;
223 public Object getOriginal() {
227 private FunctionAdapter(Function aFunction) {
228 function = aFunction;
231 public Object call(Object aParameters[]) throws GeneratorExc {
232 List parameters = new Vector();
234 for (int i = 0; i<aParameters.length; i++) {
235 parameters.add(unmakeAdapter(aParameters[i]));
238 return makeAdapter(function.perform(parameters));
241 public Object call() throws GeneratorExc {
242 return makeAdapter(function.perform(new Vector()));
245 public Object call(Object anObject) throws GeneratorExc {
246 return call(new Object[] { anObject });
249 public Object call(Object anObject1, Object anObject2) throws GeneratorExc {
250 return call(new Object[] { anObject1, anObject2 });
253 public Object call(Object anObject1, Object anObject2, Object anObject3) throws GeneratorExc {
254 return call(new Object[] { anObject1, anObject2, anObject3 });
257 public Object call(Object anObject1, Object anObject2, Object anObject3, Object anObject4) throws GeneratorExc {
258 return call(new Object[] { anObject1, anObject2, anObject3, anObject4 });
266 * <p>Description: </p>
267 * <p>Copyright: Copyright (c) 2003</p>
269 * @author not attributable
272 private static class MapAdapter implements Context, VelocityAdapter {
274 private Map valuesCache;
276 private MapAdapter(Map aMap) {
278 valuesCache = new HashMap();
281 public Object getOriginal() {
285 public boolean containsKey(Object aKey) {
286 return map.containsKey(aKey);
289 public Object get(String aKey) {
291 if (!valuesCache.containsKey(aKey)) {
292 Object value = map.get(aKey);
294 if (value == null && !map.containsKey(aKey)) {
295 return "no key "+aKey+" available";
298 valuesCache.put(aKey, makeAdapter(value));
301 return valuesCache.get(aKey);
303 catch (Throwable t) {
304 throw new GeneratorFailure(t);
308 public Object[] getKeys() {
309 return new Object[] {};
312 public Object put(String aKey, Object aValue) {
313 valuesCache.remove(aKey);
314 map.put(aKey, unmakeAdapter(aValue));
319 public Object remove(java.lang.Object key) {
327 * <p>Description: </p>
328 * <p>Copyright: Copyright (c) 2003</p>
330 * @author not attributable
333 private static class IteratorAdapter extends AbstractList implements VelocityAdapter {
334 private Iterator iterator;
335 private List valuesCache;
337 private IteratorAdapter(Iterator anIterator) {
338 iterator = anIterator;
340 valuesCache = new Vector();
342 if (iterator instanceof RewindableIterator) {
343 ((RewindableIterator) iterator).rewind();
347 private void getUntil(int anIndex) {
348 while ((anIndex==-1 || valuesCache.size()<=anIndex) && iterator.hasNext())
350 valuesCache.add(makeAdapter(iterator.next()));
354 public Object getOriginal() {
358 public Object get(int anIndex) {
363 if (anIndex<valuesCache.size())
365 result = valuesCache.get(anIndex);
370 throw new RuntimeException( "Iterator out of bounds" );
375 return valuesCache.size();
383 * <p>Description: </p>
384 * <p>Copyright: Copyright (c) 2003</p>
386 * @author not attributable
389 private static class ListAdapter extends AbstractList implements VelocityAdapter {
391 private List valuesCache;
393 private ListAdapter(List aList) {
396 valuesCache = new Vector();
399 private void getUntil(int anIndex) {
400 while ((anIndex==-1 || valuesCache.size()<=anIndex) && valuesCache.size()<list.size())
402 valuesCache.add(makeAdapter(list.get(valuesCache.size())));
406 public Object getOriginal() {
410 public Object get(int anIndex) {
415 if (anIndex<valuesCache.size())
417 result = valuesCache.get(anIndex);
422 throw new RuntimeException( "Iterator out of bounds" );
434 * <p>Description: </p>
435 * <p>Copyright: Copyright (c) 2003</p>
437 * @author not attributable
440 private static class BeanAdapter implements Context, VelocityAdapter {
441 private Object object;
443 public BeanAdapter(Object anObject) {
447 public boolean containsKey(Object key) {
451 public Object getOriginal() {
455 public Object get(String aKey) {
457 if (PropertyUtils.isReadable(object, aKey))
458 return makeAdapter(PropertyUtils.getSimpleProperty(object, aKey));
460 return makeAdapter(MethodUtils.invokeExactMethod(object, "get", aKey));
462 catch (Throwable t) {
463 throw new GeneratorFailure(t);
467 public Object[] getKeys() {
468 return new Object[] {};
471 public Object put(String aKey, Object aValue) {
473 if (PropertyUtils.isWriteable(object, aKey))
474 PropertyUtils.setSimpleProperty(object, aKey, unmakeAdapter(aValue));
476 MethodUtils.invokeExactMethod(object, "set", new Object[] {aKey, unmakeAdapter(aValue)});
480 catch (Throwable t) {
481 throw new GeneratorFailure(t);
485 public Object remove(Object aKey) {
486 throw new RuntimeException("BeanAdapter.remove not supported");
493 * <p>Description: </p>
494 * <p>Copyright: Copyright (c) 2003</p>
496 * @author not attributable
499 private static class VelocityLoggerWrapper implements LogSystem {
500 private LoggerWrapper logger;
502 public VelocityLoggerWrapper(LoggerWrapper aLogger) {
506 public void init(RuntimeServices aRuntimeServices) {
509 public void logVelocityMessage(int aLevel, String aMessage) {
512 logger.debug(aMessage);
515 logger.error(aMessage);
518 logger.info(aMessage);
521 logger.warn(aMessage);
530 * <p>Description: </p>
531 * <p>Copyright: Copyright (c) 2003</p>
533 * @author not attributable
536 public static class VelocityGeneratorLibrary implements Library {
537 private VelocityEngine engine;
539 public VelocityGeneratorLibrary(File aTemplateRoot) throws GeneratorExc, GeneratorFailure {
541 engine = new VelocityEngine();
543 engine.setProperty(VelocityEngine.RESOURCE_LOADER, "file");
544 engine.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
545 engine.setProperty("file.resource.loader.path", aTemplateRoot.getAbsolutePath());
546 engine.setProperty("file.resource.loader.cache", "true");
548 catch (Throwable t) {
549 logger.error("Error while constructing library: " + t.toString());
551 throw new GeneratorFailure(t);
555 engine.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM, new VelocityLoggerWrapper(logger));
557 catch (Throwable t) {
558 logger.error(VelocityEngine.RUNTIME_LOG_LOGSYSTEM);
563 catch (Throwable t) {
564 t.printStackTrace(logger.asPrintWriter(logger.ERROR_MESSAGE));
566 logger.error("Failed to set up a VelocityGeneratorLibrary: " + t.toString());
567 throw new GeneratorFailure(t);
571 public Generator makeGenerator(String anIdentifier) throws GeneratorExc, GeneratorFailure {
572 return new VelocityGenerator(anIdentifier, this);
579 * <p>Description: </p>
580 * <p>Copyright: Copyright (c) 2003</p>
582 * @author not attributable
585 public static class VelocityGeneratorLibraryFactory implements LibraryFactory {
586 private File basePath;
588 public VelocityGeneratorLibraryFactory(File aBasePath) {
589 basePath = aBasePath;
592 public Library makeLibrary(String anInitializationString) throws GeneratorExc, GeneratorFailure {
593 return new VelocityGeneratorLibrary(new File(basePath, anInitializationString));