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;
33 import java.io.PrintWriter;
34 import java.io.StringWriter;
35 import java.util.AbstractList;
36 import java.util.ArrayList;
37 import java.util.Date;
38 import java.util.HashMap;
39 import java.util.Iterator;
40 import java.util.List;
43 import mir.log.LoggerWrapper;
44 import mir.util.GeneratorFormatAdapters;
45 import mir.util.RewindableIterator;
47 import org.apache.commons.beanutils.MethodUtils;
48 import org.apache.commons.beanutils.PropertyUtils;
49 import org.apache.velocity.Template;
50 import org.apache.velocity.app.VelocityEngine;
51 import org.apache.velocity.context.Context;
52 import org.apache.velocity.exception.ParseErrorException;
53 import org.apache.velocity.exception.ResourceNotFoundException;
54 import org.apache.velocity.runtime.RuntimeServices;
55 import org.apache.velocity.runtime.log.LogSystem;
57 public class VelocityGenerator implements Generator {
58 private String templateIdentifier;
59 private VelocityGeneratorLibrary library;
60 private static LoggerWrapper logger = new LoggerWrapper("Generator.velocity");
68 public VelocityGenerator(String aTemplate, VelocityGeneratorLibrary aLibrary) {
69 templateIdentifier = aTemplate;
75 * @param anOutputWriter
78 * @throws GeneratorExc
79 * @throws GeneratorFailure
81 public void generate(Object anOutputWriter, Map aValues, LoggerWrapper aLogger) throws GeneratorExc, GeneratorFailure {
83 Context context = makeMapAdapter(aValues);
84 StringWriter stringWriter = new StringWriter();
87 template = library.engine.getTemplate(templateIdentifier);
88 if (template == null) {
89 throw new GeneratorExc("VelocityGeneratorLibrary: Can't find template " + templateIdentifier);
91 template.merge(context, stringWriter);
93 ( (PrintWriter) anOutputWriter).print(stringWriter.toString());
95 catch (ResourceNotFoundException t) {
96 throw new GeneratorExc("VelocityGeneratorLibrary: Can't find template " + templateIdentifier);
98 catch (ParseErrorException t) {
99 ( (PrintWriter) anOutputWriter).print(t.toString());
101 catch (Throwable t) {
102 throw new GeneratorFailure(t);
112 private static Context makeMapAdapter(Map aMap) {
113 return new MapAdapter(aMap);
121 private static List makeIteratorAdapter(Iterator anIterator) {
122 return new IteratorAdapter(anIterator);
130 private static List makeListAdapter(List aList) {
131 return new ListAdapter(aList);
139 private static Object makeFunctionAdapter(Generator.Function aFunction) {
140 return new FunctionAdapter(aFunction);
148 private static Object makeBeanAdapter(Object anObject) {
149 return new BeanAdapter(anObject);
155 * <p>Description: </p>
156 * <p>Copyright: Copyright (c) 2003</p>
158 * @author not attributable
161 private interface VelocityAdapter {
162 public Object getOriginal();
170 public static Object unmakeAdapter(Object anObject) {
171 if (anObject instanceof VelocityAdapter) {
172 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 ArrayList();
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 ArrayList()));
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 ArrayList();
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);
369 throw new RuntimeException( "Iterator out of bounds" );
374 return valuesCache.size();
382 * <p>Description: </p>
383 * <p>Copyright: Copyright (c) 2003</p>
385 * @author not attributable
388 private static class ListAdapter extends AbstractList implements VelocityAdapter {
390 private List valuesCache;
392 private ListAdapter(List aList) {
395 valuesCache = new ArrayList();
398 private void getUntil(int anIndex) {
399 while ((anIndex==-1 || valuesCache.size()<=anIndex) && valuesCache.size()<list.size())
401 valuesCache.add(makeAdapter(list.get(valuesCache.size())));
405 public Object getOriginal() {
409 public Object get(int anIndex) {
414 if (anIndex<valuesCache.size())
416 result = valuesCache.get(anIndex);
420 throw new RuntimeException( "Iterator out of bounds" );
432 * <p>Description: </p>
433 * <p>Copyright: Copyright (c) 2003</p>
435 * @author not attributable
438 private static class BeanAdapter implements Context, VelocityAdapter {
439 private Object object;
441 public BeanAdapter(Object anObject) {
445 public boolean containsKey(Object key) {
449 public Object getOriginal() {
453 public Object get(String aKey) {
455 if (PropertyUtils.isReadable(object, aKey))
456 return makeAdapter(PropertyUtils.getSimpleProperty(object, aKey));
458 return makeAdapter(MethodUtils.invokeExactMethod(object, "get", aKey));
460 catch (Throwable t) {
461 throw new GeneratorFailure(t);
465 public Object[] getKeys() {
466 return new Object[] {};
469 public Object put(String aKey, Object aValue) {
471 if (PropertyUtils.isWriteable(object, aKey))
472 PropertyUtils.setSimpleProperty(object, aKey, unmakeAdapter(aValue));
474 MethodUtils.invokeExactMethod(object, "set", new Object[] {aKey, unmakeAdapter(aValue)});
478 catch (Throwable t) {
479 throw new GeneratorFailure(t);
483 public Object remove(Object aKey) {
484 throw new RuntimeException("BeanAdapter.remove not supported");
491 * <p>Description: </p>
492 * <p>Copyright: Copyright (c) 2003</p>
494 * @author not attributable
497 private static class VelocityLoggerWrapper implements LogSystem {
499 public VelocityLoggerWrapper(LoggerWrapper aLogger) {
503 public void init(RuntimeServices aRuntimeServices) {
506 public void logVelocityMessage(int aLevel, String aMessage) {
509 logger.debug(aMessage);
512 logger.error(aMessage);
515 logger.info(aMessage);
518 logger.warn(aMessage);
527 * <p>Description: </p>
528 * <p>Copyright: Copyright (c) 2003</p>
530 * @author not attributable
533 public static class VelocityGeneratorLibrary implements Library {
534 private VelocityEngine engine;
536 public VelocityGeneratorLibrary(File aTemplateRoot) throws GeneratorExc, GeneratorFailure {
538 engine = new VelocityEngine();
540 engine.setProperty(VelocityEngine.RESOURCE_LOADER, "file");
541 engine.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
542 engine.setProperty("file.resource.loader.path", aTemplateRoot.getAbsolutePath());
543 engine.setProperty("file.resource.loader.cache", "true");
545 catch (Throwable t) {
546 logger.error("Error while constructing library: " + t.toString());
548 throw new GeneratorFailure(t);
552 engine.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM, new VelocityLoggerWrapper(logger));
554 catch (Throwable t) {
555 logger.error(VelocityEngine.RUNTIME_LOG_LOGSYSTEM);
560 catch (Throwable t) {
561 logger.error("Failed to set up a VelocityGeneratorLibrary: " + t.toString());
562 throw new GeneratorFailure(t);
566 public Generator makeGenerator(String anIdentifier) throws GeneratorExc, GeneratorFailure {
567 return new VelocityGenerator(anIdentifier, this);
574 * <p>Description: </p>
575 * <p>Copyright: Copyright (c) 2003</p>
577 * @author not attributable
580 public static class VelocityGeneratorLibraryFactory implements LibraryFactory {
581 private File basePath;
583 public VelocityGeneratorLibraryFactory(File aBasePath) {
584 basePath = aBasePath;
587 public Library makeLibrary(String anInitializationString) throws GeneratorExc, GeneratorFailure {
588 return new VelocityGeneratorLibrary(new File(basePath, anInitializationString));