small changes here and there
[mir.git] / source / mir / generator / FreemarkerGenerator.java
index fa121c7..edab67c 100755 (executable)
-/*
- * Copyright (C) 2001, 2002 The Mir-coders group
- *
- * This file is part of Mir.
- *
- * Mir is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Mir is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Mir; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * In addition, as a special exception, The Mir-coders gives permission to link
- * the code of this program with  any library licensed under the Apache Software License,
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
- * (or with modified versions of the above that use the same license as the above),
- * and distribute linked combinations including the two.  You must obey the
- * GNU General Public License in all respects for all of the code used other than
- * the above mentioned libraries.  If you modify this file, you may extend this
- * exception to your version of the file, but you are not obligated to do so.
- * If you do not wish to do so, delete this exception statement from your version.
- */
-package mir.generator;
-
-import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Vector;
-
-import mir.log.LoggerWrapper;
-import mir.util.*;
-
-import org.apache.commons.beanutils.*;
-
-import freemarker.template.FileTemplateCache;
-import freemarker.template.SimpleScalar;
-import freemarker.template.Template;
-import freemarker.template.TemplateHashModel;
-import freemarker.template.TemplateListModel;
-import freemarker.template.TemplateMethodModel;
-import freemarker.template.TemplateModel;
-import freemarker.template.TemplateModelException;
-import freemarker.template.TemplateModelRoot;
-import freemarker.template.TemplateScalarModel;
-
-
-public class FreemarkerGenerator implements Generator {
-  private Template template;
-
-  public FreemarkerGenerator(Template aTemplate) {
-    template = aTemplate;
-  }
-
-  public void generate(Object anOutputWriter, Map aValues, LoggerWrapper aLogger) throws GeneratorExc, GeneratorFailure {
-    if (!(anOutputWriter instanceof PrintWriter))
-      throw new GeneratorExc("Writer for a FreemarkerGenerator must be a PrintWriter");
-
-    try {
-      template.process((TemplateModelRoot) makeMapAdapter(aValues), (PrintWriter) anOutputWriter);
-    }
-    catch (Throwable t) {
-      t.printStackTrace();
-      aLogger.error("Exception occurred: "+t.getMessage());
-      t.printStackTrace(aLogger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));
-      throw new GeneratorFailure( t );
-    }
-  }
-
-  private static TemplateScalarModel makeStringAdapter(String aString) {
-    return new SimpleScalar(aString);
-  }
-
-  private static TemplateHashModel makeMapAdapter(Map aMap)  {
-    return new MapAdapter(aMap);
-  }
-
-  private static TemplateListModel makeIteratorAdapter(Iterator anIterator) {
-    return new IteratorAdapter(anIterator);
-  }
-
-  private static TemplateMethodModel makeFunctionAdapter(Generator.GeneratorFunction aFunction) {
-    return new FunctionAdapter(aFunction);
-  }
-
-  private static TemplateHashModel makeBeanAdapter(Object anObject)  {
-    return new BeanAdapter(anObject);
-  }
-
-  public static TemplateModel makeAdapter(Object anObject) throws TemplateModelException {
-    if (anObject == null)
-      return null;
-
-    if (anObject instanceof TemplateModel)
-      return (TemplateModel) anObject;
-    else if (anObject instanceof Generator.GeneratorFunction)
-      return makeFunctionAdapter((Generator.GeneratorFunction) anObject);
-    else if (anObject instanceof Integer)
-      return makeStringAdapter(((Integer) anObject).toString());
-    else if (anObject instanceof Boolean) {
-      if (((Boolean) anObject).booleanValue())
-        return makeStringAdapter("1");
-      else
-        return makeStringAdapter("0");
-    }
-    else if (anObject instanceof String)
-      return makeStringAdapter((String) anObject);
-    else if (anObject instanceof Map)
-      return makeMapAdapter((Map) anObject);
-    else if (anObject instanceof Iterator)
-      return makeIteratorAdapter((Iterator) anObject);
-    else if (anObject instanceof List)
-      return makeIteratorAdapter(((List) anObject).iterator());
-    else if (anObject instanceof Number)
-      return makeAdapter(new GeneratorFormatAdapters.NumberFormatAdapter((Number) anObject));
-    else
-      return makeBeanAdapter(anObject);
-  }
-
-  private static class MapAdapter implements TemplateModelRoot {
-    private Map map;
-    private Map valuesCache;
-
-    private MapAdapter(Map aMap) {
-      map = aMap;
-      valuesCache = new HashMap();
-    }
-
-    public void put(String aKey, TemplateModel aModel) {
-      valuesCache.put(aKey, aModel);
-    }
-
-    public void remove(String aKey) {
-      // ML: kinda tricky...
-    }
-
-    public boolean isEmpty() {
-      return map.isEmpty();
-    }
-
-    public TemplateModel get(String aKey) throws TemplateModelException {
-      try {
-        if (!valuesCache.containsKey(aKey)) {
-          Object value = map.get(aKey);
-
-          if (value == null && !map.containsKey(aKey)) {
-            throw new TemplateModelException("MapAdapter: no key "+aKey+" available");
-          }
-
-          valuesCache.put(aKey, makeAdapter(value));
-        }
-
-        return (TemplateModel) valuesCache.get(aKey);
-      }
-      catch (TemplateModelException e) {
-        throw e;
-      }
-      catch (Throwable t) {
-        throw new TemplateModelException(t.getMessage());
-      }
-    }
-  }
-
-  private static class IteratorAdapter implements TemplateListModel {
-    private Iterator iterator;
-    private List valuesCache;
-    private int position;
-
-    private IteratorAdapter(Iterator anIterator) {
-      iterator = anIterator;
-
-      valuesCache = new Vector();
-      position=0;
-
-
-      if (iterator instanceof RewindableIterator) {
-        ((RewindableIterator) iterator).rewind();
-      }
-    }
-
-    public boolean isEmpty() {
-      return valuesCache.isEmpty() && !iterator.hasNext();
-    }
-
-    private void getUntil(int anIndex) throws TemplateModelException {
-      while (valuesCache.size()<=anIndex && iterator.hasNext())
-      {
-        valuesCache.add(makeAdapter(iterator.next()));
-      }
-    };
-
-    public TemplateModel get(int anIndex) throws TemplateModelException {
-      TemplateModel result;
-
-      getUntil(anIndex);
-
-      if (anIndex<valuesCache.size())
-      {
-        result = (TemplateModel) valuesCache.get(anIndex);
-
-        return result;
-      }
-      else
-        throw new TemplateModelException( "Iterator out of bounds" );
-    }
-
-    public boolean hasNext() {
-      return position<valuesCache.size() || iterator.hasNext();
-    }
-
-    public boolean isRewound() {
-      return position==0;
-    }
-
-    public TemplateModel next() throws TemplateModelException {
-      TemplateModel result;
-
-      if (hasNext()) {
-        result = get(position);
-        position++;
-      }
-      else
-        throw new TemplateModelException( "Iterator out of bounds" );
-
-      return result;
-    }
-
-    public void rewind() {
-      position=0;
-    }
-  }
-
-  private static class ListAdapter implements TemplateListModel {
-    List list;
-    List valuesCache;
-    int position;
-
-    private ListAdapter(List aList) {
-      list = aList;
-      valuesCache = new Vector();
-      position=0;
-    }
-
-    public boolean isEmpty() {
-      return list.isEmpty();
-    }
-
-    public TemplateModel get(int i) throws TemplateModelException {
-
-      if (i>=valuesCache.size() && i<list.size()) {
-        for(int j=valuesCache.size(); j<=i; j++) {
-          valuesCache.add(makeAdapter(list.get(j)));
-        }
-      }
-
-      if (i<valuesCache.size())
-        return (TemplateModel) valuesCache.get(i);
-      else
-        throw new TemplateModelException( "Iterator out of bounds" );
-    }
-
-    public boolean hasNext() {
-      return position<list.size();
-    }
-
-    public boolean isRewound() {
-      return position==0;
-    }
-
-    public TemplateModel next() throws TemplateModelException {
-      TemplateModel result;
-
-      if (hasNext()) {
-        result = get(position);
-        position++;
-      }
-      else {
-        throw new TemplateModelException( "Iterator out of bounds" );
-      }
-
-      return result;
-    }
-
-    public void rewind() {
-      position = 0;
-    }
-  }
-
-  private static class FunctionAdapter implements TemplateMethodModel {
-    private Generator.GeneratorFunction function;
-
-    public FunctionAdapter(Generator.GeneratorFunction aFunction) {
-      function = aFunction;
-    }
-
-    public TemplateModel exec(List anArguments) throws TemplateModelException {
-      try {
-        return makeAdapter(function.perform(anArguments));
-      }
-      catch (Throwable t) {
-        throw new TemplateModelException(t.getMessage());
-      }
-    }
-
-    public boolean isEmpty() {
-      return false;
-    }
-
-  }
-
-  private static class BeanAdapter implements TemplateHashModel {
-    private Object object;
-
-    public BeanAdapter(Object anObject) {
-      object = anObject;
-    }
-
-    public void put(String aKey, TemplateModel aModel)  throws TemplateModelException  {
-      throw new TemplateModelException("FreemarkerGenerator$BeanAdapter.put not supported");
-    }
-
-    public void remove(String aKey) throws TemplateModelException  {
-      throw new TemplateModelException("FreemarkerGenerator$BeanAdapter.remove not supported");
-    }
-
-    public boolean isEmpty() {
-      return false;
-    }
-
-    public TemplateModel get(String aKey) throws TemplateModelException {
-      try {
-        if (PropertyUtils.isReadable(object, aKey))
-          return makeAdapter(PropertyUtils.getSimpleProperty(object, aKey));
-        else
-          return makeAdapter(MethodUtils.invokeExactMethod(object, "get", aKey));
-      }
-      catch (Throwable t) {
-        throw new TemplateModelException(t.getMessage());
-      }
-    }
-  }
-
-  public static class FreemarkerGeneratorLibrary implements GeneratorLibrary {
-    private FileTemplateCache templateCache;
-
-    public FreemarkerGeneratorLibrary(String aTemplateRoot) {
-      templateCache = new FileTemplateCache( aTemplateRoot+"/" );
-      templateCache.setLoadingPolicy(FileTemplateCache.LOAD_ON_DEMAND);
-    }
-
-    public Generator makeGenerator(String anIdentifier) throws GeneratorExc, GeneratorFailure {
-      Template template = (Template) templateCache.getItem(anIdentifier, "template");
-
-      if (template==null) {
-        throw new GeneratorExc("FreemarkerGeneratorLibrary: Can't find template "+templateCache.getDirectory()+anIdentifier);
-      }
-
-      return new FreemarkerGenerator(template);
-    }
-  }
-
-  public static class FreemarkerGeneratorLibraryFactory implements GeneratorLibraryFactory {
-    private String basePath;
-
-    public FreemarkerGeneratorLibraryFactory(String aBasePath) {
-      basePath = aBasePath;
-    }
-
-    public GeneratorLibrary makeLibrary(String anInitializationString) {
-      return new FreemarkerGeneratorLibrary(basePath+anInitializationString);
-    };
-  }
-}
+/*\r
+ * Copyright (C) 2001, 2002 The Mir-coders group\r
+ *\r
+ * This file is part of Mir.\r
+ *\r
+ * Mir is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * Mir is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with Mir; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *\r
+ * In addition, as a special exception, The Mir-coders gives permission to link\r
+ * the code of this program with  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.generator;\r
+\r
+import java.io.PrintWriter;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Vector;\r
+\r
+import org.apache.commons.beanutils.MethodUtils;\r
+import org.apache.commons.beanutils.PropertyUtils;\r
+\r
+import freemarker.template.FileTemplateCache;\r
+import freemarker.template.SimpleScalar;\r
+import freemarker.template.Template;\r
+import freemarker.template.TemplateHashModel;\r
+import freemarker.template.TemplateListModel;\r
+import freemarker.template.TemplateMethodModel;\r
+import freemarker.template.TemplateModel;\r
+import freemarker.template.TemplateModelException;\r
+import freemarker.template.TemplateModelRoot;\r
+import freemarker.template.TemplateScalarModel;\r
+\r
+import mir.log.LoggerWrapper;\r
+import mir.util.GeneratorFormatAdapters;\r
+import mir.util.RewindableIterator;\r
+\r
+\r
+public class FreemarkerGenerator implements Generator {\r
+  private Template template;\r
+\r
+  public FreemarkerGenerator(Template aTemplate) {\r
+    template = aTemplate;\r
+  }\r
+\r
+  public void generate(Object anOutputWriter, Map aValues, LoggerWrapper aLogger) throws GeneratorExc, GeneratorFailure {\r
+    if (!(anOutputWriter instanceof PrintWriter))\r
+      throw new GeneratorExc("Writer for a FreemarkerGenerator must be a PrintWriter");\r
+\r
+    try {\r
+      template.process((TemplateModelRoot) makeMapAdapter(aValues), (PrintWriter) anOutputWriter);\r
+    }\r
+    catch (Throwable t) {\r
+      t.printStackTrace();\r
+      aLogger.error("Exception occurred: "+t.getMessage());\r
+      t.printStackTrace(aLogger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));\r
+      throw new GeneratorFailure( t );\r
+    }\r
+  }\r
+\r
+  private static TemplateScalarModel makeStringAdapter(String aString) {\r
+    return new SimpleScalar(aString);\r
+  }\r
+\r
+  private static TemplateHashModel makeMapAdapter(Map aMap)  {\r
+    return new MapAdapter(aMap);\r
+  }\r
+\r
+  private static TemplateListModel makeIteratorAdapter(Iterator anIterator) {\r
+    return new IteratorAdapter(anIterator);\r
+  }\r
+\r
+  private static TemplateMethodModel makeFunctionAdapter(Generator.GeneratorFunction aFunction) {\r
+    return new FunctionAdapter(aFunction);\r
+  }\r
+\r
+  private static TemplateHashModel makeBeanAdapter(Object anObject)  {\r
+    return new BeanAdapter(anObject);\r
+  }\r
+\r
+  public static TemplateModel makeAdapter(Object anObject) throws TemplateModelException {\r
+    if (anObject == null)\r
+      return null;\r
+\r
+    if (anObject instanceof TemplateModel)\r
+      return (TemplateModel) anObject;\r
+    else if (anObject instanceof Generator.GeneratorFunction)\r
+      return makeFunctionAdapter((Generator.GeneratorFunction) anObject);\r
+    else if (anObject instanceof Integer)\r
+      return makeStringAdapter(((Integer) anObject).toString());\r
+    else if (anObject instanceof Boolean) {\r
+      if (((Boolean) anObject).booleanValue())\r
+        return makeStringAdapter("1");\r
+      else\r
+        return makeStringAdapter("0");\r
+    }\r
+    else if (anObject instanceof String)\r
+      return makeStringAdapter((String) anObject);\r
+    else if (anObject instanceof Map)\r
+      return makeMapAdapter((Map) anObject);\r
+    else if (anObject instanceof Iterator)\r
+      return makeIteratorAdapter((Iterator) anObject);\r
+    else if (anObject instanceof List)\r
+      return makeIteratorAdapter(((List) anObject).iterator());\r
+    else if (anObject instanceof Number)\r
+      return makeAdapter(new GeneratorFormatAdapters.NumberFormatAdapter((Number) anObject));\r
+    else\r
+      return makeBeanAdapter(anObject);\r
+  }\r
+\r
+  private static class MapAdapter implements TemplateModelRoot {\r
+    private Map map;\r
+    private Map valuesCache;\r
+\r
+    private MapAdapter(Map aMap) {\r
+      map = aMap;\r
+      valuesCache = new HashMap();\r
+    }\r
+\r
+    public void put(String aKey, TemplateModel aModel) {\r
+      valuesCache.put(aKey, aModel);\r
+    }\r
+\r
+    public void remove(String aKey) {\r
+      // ML: kinda tricky...\r
+    }\r
+\r
+    public boolean isEmpty() {\r
+      return map.isEmpty();\r
+    }\r
+\r
+    public TemplateModel get(String aKey) throws TemplateModelException {\r
+      try {\r
+        if (!valuesCache.containsKey(aKey)) {\r
+          Object value = map.get(aKey);\r
+\r
+          if (value == null && !map.containsKey(aKey)) {\r
+            throw new TemplateModelException("MapAdapter: no key "+aKey+" available");\r
+          }\r
+\r
+          valuesCache.put(aKey, makeAdapter(value));\r
+        }\r
+\r
+        return (TemplateModel) valuesCache.get(aKey);\r
+      }\r
+      catch (TemplateModelException e) {\r
+        throw e;\r
+      }\r
+      catch (Throwable t) {\r
+        throw new TemplateModelException(t.getMessage());\r
+      }\r
+    }\r
+  }\r
+\r
+  private static class IteratorAdapter implements TemplateListModel {\r
+    private Iterator iterator;\r
+    private List valuesCache;\r
+    private int position;\r
+\r
+    private IteratorAdapter(Iterator anIterator) {\r
+      iterator = anIterator;\r
+\r
+      valuesCache = new Vector();\r
+      position=0;\r
+\r
+\r
+      if (iterator instanceof RewindableIterator) {\r
+        ((RewindableIterator) iterator).rewind();\r
+      }\r
+    }\r
+\r
+    public boolean isEmpty() {\r
+      return valuesCache.isEmpty() && !iterator.hasNext();\r
+    }\r
+\r
+    private void getUntil(int anIndex) throws TemplateModelException {\r
+      while (valuesCache.size()<=anIndex && iterator.hasNext())\r
+      {\r
+        valuesCache.add(makeAdapter(iterator.next()));\r
+      }\r
+    };\r
+\r
+    public TemplateModel get(int anIndex) throws TemplateModelException {\r
+      TemplateModel result;\r
+\r
+      getUntil(anIndex);\r
+\r
+      if (anIndex<valuesCache.size())\r
+      {\r
+        result = (TemplateModel) valuesCache.get(anIndex);\r
+\r
+        return result;\r
+      }\r
+      else\r
+        throw new TemplateModelException( "Iterator out of bounds" );\r
+    }\r
+\r
+    public boolean hasNext() {\r
+      return position<valuesCache.size() || iterator.hasNext();\r
+    }\r
+\r
+    public boolean isRewound() {\r
+      return position==0;\r
+    }\r
+\r
+    public TemplateModel next() throws TemplateModelException {\r
+      TemplateModel result;\r
+\r
+      if (hasNext()) {\r
+        result = get(position);\r
+        position++;\r
+      }\r
+      else\r
+        throw new TemplateModelException( "Iterator out of bounds" );\r
+\r
+      return result;\r
+    }\r
+\r
+    public void rewind() {\r
+      position=0;\r
+    }\r
+  }\r
+\r
+  private static class ListAdapter implements TemplateListModel {\r
+    List list;\r
+    List valuesCache;\r
+    int position;\r
+\r
+    private ListAdapter(List aList) {\r
+      list = aList;\r
+      valuesCache = new Vector();\r
+      position=0;\r
+    }\r
+\r
+    public boolean isEmpty() {\r
+      return list.isEmpty();\r
+    }\r
+\r
+    public TemplateModel get(int i) throws TemplateModelException {\r
+\r
+      if (i>=valuesCache.size() && i<list.size()) {\r
+        for(int j=valuesCache.size(); j<=i; j++) {\r
+          valuesCache.add(makeAdapter(list.get(j)));\r
+        }\r
+      }\r
+\r
+      if (i<valuesCache.size())\r
+        return (TemplateModel) valuesCache.get(i);\r
+      else\r
+        throw new TemplateModelException( "Iterator out of bounds" );\r
+    }\r
+\r
+    public boolean hasNext() {\r
+      return position<list.size();\r
+    }\r
+\r
+    public boolean isRewound() {\r
+      return position==0;\r
+    }\r
+\r
+    public TemplateModel next() throws TemplateModelException {\r
+      TemplateModel result;\r
+\r
+      if (hasNext()) {\r
+        result = get(position);\r
+        position++;\r
+      }\r
+      else {\r
+        throw new TemplateModelException( "Iterator out of bounds" );\r
+      }\r
+\r
+      return result;\r
+    }\r
+\r
+    public void rewind() {\r
+      position = 0;\r
+    }\r
+  }\r
+\r
+  private static class FunctionAdapter implements TemplateMethodModel {\r
+    private Generator.GeneratorFunction function;\r
+\r
+    public FunctionAdapter(Generator.GeneratorFunction aFunction) {\r
+      function = aFunction;\r
+    }\r
+\r
+    public TemplateModel exec(List anArguments) throws TemplateModelException {\r
+      try {\r
+        return makeAdapter(function.perform(anArguments));\r
+      }\r
+      catch (Throwable t) {\r
+        throw new TemplateModelException(t.getMessage());\r
+      }\r
+    }\r
+\r
+    public boolean isEmpty() {\r
+      return false;\r
+    }\r
+\r
+  }\r
+\r
+  private static class BeanAdapter implements TemplateHashModel {\r
+    private Object object;\r
+\r
+    public BeanAdapter(Object anObject) {\r
+      object = anObject;\r
+    }\r
+\r
+    public void put(String aKey, TemplateModel aModel)  throws TemplateModelException  {\r
+      throw new TemplateModelException("FreemarkerGenerator$BeanAdapter.put not supported");\r
+    }\r
+\r
+    public void remove(String aKey) throws TemplateModelException  {\r
+      throw new TemplateModelException("FreemarkerGenerator$BeanAdapter.remove not supported");\r
+    }\r
+\r
+    public boolean isEmpty() {\r
+      return false;\r
+    }\r
+\r
+    public TemplateModel get(String aKey) throws TemplateModelException {\r
+      try {\r
+        if (PropertyUtils.isReadable(object, aKey))\r
+          return makeAdapter(PropertyUtils.getSimpleProperty(object, aKey));\r
+        else\r
+          return makeAdapter(MethodUtils.invokeExactMethod(object, "get", aKey));\r
+      }\r
+      catch (Throwable t) {\r
+        throw new TemplateModelException(t.getMessage());\r
+      }\r
+    }\r
+  }\r
+\r
+  public static class FreemarkerGeneratorLibrary implements GeneratorLibrary {\r
+    private FileTemplateCache templateCache;\r
+\r
+    public FreemarkerGeneratorLibrary(String aTemplateRoot) {\r
+      templateCache = new FileTemplateCache( aTemplateRoot+"/" );\r
+      templateCache.setLoadingPolicy(FileTemplateCache.LOAD_ON_DEMAND);\r
+    }\r
+\r
+    public Generator makeGenerator(String anIdentifier) throws GeneratorExc, GeneratorFailure {\r
+      Template template = (Template) templateCache.getItem(anIdentifier, "template");\r
+\r
+      if (template==null) {\r
+        throw new GeneratorExc("FreemarkerGeneratorLibrary: Can't find template "+templateCache.getDirectory()+anIdentifier);\r
+      }\r
+\r
+      return new FreemarkerGenerator(template);\r
+    }\r
+  }\r
+\r
+  public static class FreemarkerGeneratorLibraryFactory implements GeneratorLibraryFactory {\r
+    private String basePath;\r
+\r
+    public FreemarkerGeneratorLibraryFactory(String aBasePath) {\r
+      basePath = aBasePath;\r
+    }\r
+\r
+    public GeneratorLibrary makeLibrary(String anInitializationString) {\r
+      return new FreemarkerGeneratorLibrary(basePath+anInitializationString);\r
+    };\r
+  }\r
+}\r