1 /* 2 * Copyright (c) 2005 The Visigoth Software Society. All rights 3 * reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * 3. The end-user documentation included with the redistribution, if 18 * any, must include the following acknowledgement: 19 * "This product includes software developed by the 20 * Visigoth Software Society (http://www.visigoths.org/)." 21 * Alternately, this acknowledgement may appear in the software itself, 22 * if and wherever such third-party acknowledgements normally appear. 23 * 24 * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the 25 * project contributors may be used to endorse or promote products derived 26 * from this software without prior written permission. For written 27 * permission, please contact visigoths@visigoths.org. 28 * 29 * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" 30 * nor may "FreeMarker" or "Visigoth" appear in their names 31 * without prior written permission of the Visigoth Software Society. 32 * 33 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 34 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 35 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 36 * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR 37 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 38 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 39 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 40 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 41 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 42 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 43 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44 * SUCH DAMAGE. 45 * ==================================================================== 46 * 47 * This software consists of voluntary contributions made by many 48 * individuals on behalf of the Visigoth Software Society. For more 49 * information on the Visigoth Software Society, please see 50 * http://www.visigoths.org/ 51 */ 52 53 package freemarker.cache; 54 55 import java.io.Reader; 56 import java.io.StringReader; 57 import java.util.HashMap; 58 import java.util.Map; 59 60 /** 61 * A {@link TemplateLoader} that uses a Map with Strings as its source of 62 * templates. 63 * 64 * In most case the regular way of loading templates from files will be fine. 65 * However, there can be situations where you don't want to or can't load a 66 * template from a file, e.g. if you have to deploy a single jar for 67 * JavaWebStart or if they are contained within a database. 68 * A single template can be created manually 69 * e.g. 70 * <pre> 71 * String templateStr="Hello ${user}"; 72 * Template t = new Template("name", new StringReader(templateStr), 73 * new Configuration()); 74 * </pre> 75 * If, however, you want to create templates from strings which import other 76 * templates this method doesn't work. 77 * 78 * In that case you can create a StringTemplateLoader and add each template to 79 * it: 80 * <pre> 81 * StringTemplateLoader stringLoader = new StringTemplateLoader(); 82 * stringLoader.putTemplate("greetTemplate", "<#macro greet>Hello</#macro>"); 83 * stringLoader.putTemplate("myTemplate", "<#include \"greetTemplate\"><@greet/> World!"); 84 * </pre> 85 * Then you tell your Configuration object to use it: 86 * <pre> 87 * cfg.setTemplateLoader(stringLoader); 88 * </pre> 89 * After that you should be able to use the templates as usual. Often you will 90 * want to combine a <tt>StringTemplateLoader</tt> with another loader. You can 91 * do so using a {@link freemarker.cache.MultiTemplateLoader}. 92 * 93 * @version $Id: v 1.0 2005/04/01 94 * @author Meikel Bisping 95 * @author Attila Szegedi 96 * @version $Id: StringTemplateLoader.java,v 1.1 2005/04/08 11:47:53 szegedia Exp $ 97 */ 98 public class StringTemplateLoader implements TemplateLoader { 99 private final Map templates = new HashMap(); 100 101 /** 102 * Puts a template into the loader. A call to this method is identical to 103 * the call to the three-arg {@link #putTemplate(String, String, long)} 104 * passing <tt>System.currentTimeMillis()</tt> as the third argument. 105 * @param name the name of the template. 106 * @param templateSource the source code of the template. 107 */ 108 public void putTemplate(String name, String templateSource) { 109 putTemplate(name, templateSource, System.currentTimeMillis()); 110 } 111 112 /** 113 * Puts a template into the loader. The name can contain slashes to denote 114 * logical directory structure, but must not start with a slash. If the 115 * method is called multiple times for the same name and with different 116 * last modified time, the configuration's template cache will reload the 117 * template according to its own refresh settings (note that if the refresh 118 * is disabled in the template cache, the template will not be reloaded). 119 * Also, since the cache uses lastModified to trigger reloads, calling the 120 * method with different source and identical timestamp won't trigger 121 * reloading. 122 * @param name the name of the template. 123 * @param templateSource the source code of the template. 124 * @param lastModified the time of last modification of the template in 125 * terms of <tt>System.currentTimeMillis()</tt> 126 */ 127 public void putTemplate(String name, String templateSource, long lastModified) { 128 templates.put(name, new StringTemplateSource(name, templateSource, lastModified)); 129 } 130 131 public void closeTemplateSource(Object templateSource) { 132 } 133 134 public Object findTemplateSource(String name) { 135 return templates.get(name); 136 } 137 138 public long getLastModified(Object templateSource) { 139 return ((StringTemplateSource)templateSource).lastModified; 140 } 141 142 public Reader getReader(Object templateSource, String encoding) { 143 return new StringReader(((StringTemplateSource)templateSource).source); 144 } 145 146 private static class StringTemplateSource { 147 private final String name; 148 private final String source; 149 private final long lastModified; 150 151 StringTemplateSource(String name, String source, long lastModified) { 152 if(name == null) { 153 throw new IllegalArgumentException("name == null"); 154 } 155 if(source == null) { 156 throw new IllegalArgumentException("source == null"); 157 } 158 if(lastModified < -1L) { 159 throw new IllegalArgumentException("lastModified < -1L"); 160 } 161 this.name = name; 162 this.source = source; 163 this.lastModified = lastModified; 164 } 165 166 public boolean equals(Object obj) { 167 if(obj instanceof StringTemplateSource) { 168 return name.equals(((StringTemplateSource)obj).name); 169 } 170 return false; 171 } 172 173 public int hashCode() { 174 return name.hashCode(); 175 } 176 } 177 }