View Javadoc

1   /*
2    * $Source: /usr/cvsroot/melati/melati/src/main/java/org/melati/template/ClassNameTempletLoader.java,v $
3    * $Revision: 1.37 $
4    *
5    * Copyright (C) 2000 William Chesters
6    *
7    * Part of Melati (http://melati.org), a framework for the rapid
8    * development of clean, maintainable web applications.
9    *
10   * Melati is free software; Permission is granted to copy, distribute
11   * and/or modify this software under the terms either:
12   *
13   * a) the GNU General Public License as published by the Free Software
14   *    Foundation; either version 2 of the License, or (at your option)
15   *    any later version,
16   *
17   *    or
18   *
19   * b) any version of the Melati Software License, as published
20   *    at http://melati.org
21   *
22   * You should have received a copy of the GNU General Public License and
23   * the Melati Software License along with this program;
24   * if not, write to the Free Software Foundation, Inc.,
25   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26   * GNU General Public License and visit http://melati.org to obtain the
27   * Melati Software License.
28   *
29   * Feel free to contact the Developers of Melati (http://melati.org),
30   * if you would like to work out a different arrangement than the options
31   * outlined here.  It is our intention to allow Melati to be used by as
32   * wide an audience as possible.
33   *
34   * This program is distributed in the hope that it will be useful,
35   * but WITHOUT ANY WARRANTY; without even the implied warranty of
36   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37   * GNU General Public License for more details.
38   *
39   * Contact details for copyright holder:
40   *
41   *     William Chesters <williamc At paneris.org>
42   *     http://paneris.org/~williamc
43   *     Obrechtstraat 114, 2517VX Den Haag, The Netherlands
44   */
45  
46  package org.melati.template;
47  
48  import java.io.IOException;
49  import java.util.Hashtable;
50  
51  import org.melati.poem.FieldAttributes;
52  import org.melati.util.MelatiBugMelatiException;
53  
54  /**
55   * Load a template to render an object based upon the object's class.
56   */
57  public final class ClassNameTempletLoader implements TempletLoader {
58  
59    /** The instance. */
60    private static ClassNameTempletLoader it = null;
61  
62    // NOTE It is not expected that templates will be added at runtime.
63    private static Hashtable templetForClassCache = new Hashtable();
64    
65    private static final Integer FOUND = new Integer(1);
66    private static final Integer NOT_FOUND = new Integer(0);
67    private static Hashtable lookedupTemplateNames = new Hashtable();
68  
69    /** Disable instantiation. */
70    private ClassNameTempletLoader() {}
71  
72    /**
73     * @return the instance
74     */
75    public static ClassNameTempletLoader getInstance() {
76      if (it == null)
77        it = new ClassNameTempletLoader();
78      return it;
79    }
80    protected static String templetsPath(TemplateEngine templateEngine, 
81                                  MarkupLanguage markupLanguage) {
82      /*
83      // Fails to find templates in jars!!
84      return "org" + File.separatorChar + 
85             "melati" + File.separatorChar + 
86             "template" + File.separatorChar + 
87              templateEngine.getName() + File.separatorChar + 
88             "templets" + File.separatorChar +
89              markupLanguage.getName() + File.separatorChar;
90      */
91      return "org/melati/template/" +  
92             templateEngine.getName() +  
93             "/templets/" + 
94             markupLanguage.getName() + "/";
95      
96      }
97  
98    /**
99     * @return the path in the templets directory
100    */
101   protected static String templetsTempletPath(TemplateEngine templateEngine,
102                                MarkupLanguage markupLanguage,
103                                String purpose, String name) {
104     if (purpose == null)
105       return 
106                  templetsPath(templateEngine, markupLanguage) + 
107                  name +
108                  templateEngine.templateExtension();
109     return 
110                templetsPath(templateEngine, markupLanguage) + 
111                purpose + "/" + 
112                name +
113                templateEngine.templateExtension();
114   }
115 
116   protected static String classpathTempletPath(Class clazz, TemplateEngine templateEngine) { 
117     return clazz.getName().replace('.', '/') + templateEngine.templateExtension();
118   }
119   /**
120    * Get a templet by name, with optional purpose. 
121    * 
122    * {@inheritDoc}
123    * @see TempletLoader#templet(TemplateEngine, AbstractMarkupLanguage, String, String)
124    */
125   public Template templet(TemplateEngine templateEngine,
126                           MarkupLanguage markupLanguage, String purpose,
127                           String name) throws IOException, NotFoundException {
128     return templateEngine.template(templetsTempletPath(templateEngine, markupLanguage,
129         purpose, name));
130   }
131 
132   /**
133    * Get a templet by its name, looking only in the templets directory.
134    * 
135    * {@inheritDoc}
136    * @see TempletLoader#templet(TemplateEngine, MarkupLanguage, String)
137    */
138   public Template templet(TemplateEngine templateEngine,
139                           MarkupLanguage markupLanguage, String name) 
140       throws IOException, NotFoundException {
141     return templet(templateEngine, markupLanguage, null, name);
142   }
143 
144   /**
145    * Get a templet based upon class name and optional purpose, 
146    * looking in the templets directory and also the classpath.
147    * 
148    * {@inheritDoc}
149    * @see TempletLoader#templet(TemplateEngine, MarkupLanguage, 
150    *                            String, Class)
151    */
152   public Template templet(TemplateEngine templateEngine,
153                           MarkupLanguage markupLanguage, String purpose,
154                           Class clazz)
155       throws TemplateEngineException, IOException {
156     Class lookupClass = clazz;
157     Template templet = null;
158     Template fromCache = null;
159     String originalCacheKey = cacheKey(templateEngine, markupLanguage, purpose, lookupClass);
160     String lookupCacheKey = originalCacheKey;
161     String lookupPurpose = purpose;
162     while (lookupClass != null) {
163       fromCache = (Template)templetForClassCache.get(lookupCacheKey);
164       if (fromCache != null) {
165         templet = fromCache;
166         break;
167       } 
168       //templet = getSpecialTemplate(lookupClass, lookupPurpose, markupLanguage, templateEngine);
169       //if (templet != null)
170       //  break;
171       
172       // Try to find one in the templets directory
173       String templetPath = templetsTempletPath(templateEngine, markupLanguage,
174               lookupPurpose, lookupClass.getName());
175       templet = getTemplate(templateEngine, templetPath);
176       if (templet != null)
177         break;
178       // Try to find one on classpath
179       templetPath = classpathTempletPath(lookupClass, templateEngine);
180       templet = getTemplate(templateEngine, templetPath);
181       if (templet != null)
182         break;
183       
184       if (lookupPurpose != null)
185         lookupPurpose = null;
186       else { 
187         lookupClass = lookupClass.getSuperclass();
188         lookupPurpose = purpose;
189       }
190       lookupCacheKey = cacheKey(templateEngine, markupLanguage, lookupPurpose, lookupClass);
191     }
192     
193     if (templet == null)
194       throw new MelatiBugMelatiException("Cannot even find template for Object");
195     if (fromCache == null)
196       templetForClassCache.put(originalCacheKey, templet);
197     if (!lookupCacheKey.equals(originalCacheKey)) { 
198       if (templetForClassCache.get(lookupCacheKey) == null) 
199         templetForClassCache.put(lookupCacheKey, templet);
200     } 
201     return templet;
202   }
203 
204   private String cacheKey(TemplateEngine templateEngine, 
205       MarkupLanguage markupLanguage, 
206       String purpose, 
207       Class lookupClass) {
208     return  purpose == null ? cacheKey(templateEngine, markupLanguage, lookupClass) 
209                             : lookupClass + "/" + 
210                                purpose + "/" + 
211                                markupLanguage + "/" + 
212                                templateEngine.getName();
213   }
214   
215   private String cacheKey(TemplateEngine templateEngine, 
216       MarkupLanguage markupLanguage, 
217       Class lookupClass) {
218     return lookupClass + 
219            "/" + markupLanguage + 
220            "/" + templateEngine.getName();
221   }
222 
223   private Template getTemplate(TemplateEngine templateEngine, String templetPath) 
224       throws IOException { 
225     Template templet = null;
226     try {
227       Object triedAlready = lookedupTemplateNames.get(templetPath);
228       if (triedAlready != NOT_FOUND) {
229         templet = templateEngine.template(templetPath);
230         lookedupTemplateNames.put(templetPath, FOUND);
231       } 
232     } catch (NotFoundException e) {
233       lookedupTemplateNames.put(templetPath, NOT_FOUND);
234     }
235     return templet;
236   }
237 
238   /**
239    * Get a templet for a class.
240    * 
241    * {@inheritDoc}
242    * @see TempletLoader#templet(TemplateEngine, MarkupLanguage, Class)
243    */
244   public Template templet(TemplateEngine templateEngine,
245                           MarkupLanguage markupLanguage, Class clazz)
246       throws IOException {
247     return templet(templateEngine, markupLanguage, null, clazz);
248   }
249 
250   /**
251    * Get a templet either from the FieldAttributes or 
252    * the class name.
253    * 
254    * {@inheritDoc}
255    * @see TempletLoader#templet(TemplateEngine,MarkupLanguage,FieldAttributes)
256    */
257   public Template templet(TemplateEngine templateEngine,
258                           MarkupLanguage markupLanguage,
259                           FieldAttributes attributes)
260       throws IOException {
261     if (attributes.getRenderInfo() != null) {
262       String templetName = attributes.getType().getClass().getName() 
263           + "-"
264           + attributes.getRenderInfo();
265       try {
266         return templet(templateEngine, markupLanguage, 
267                 templetName);
268       } catch (NotFoundException e) {
269         throw new MelatiBugMelatiException(
270                 "Templet " + templetName  + " not found", e);
271       }
272     } else {
273         return templet(templateEngine, markupLanguage,
274                 attributes.getType().getClass());
275     }
276   }
277 }
278 
279 
280 
281 
282 
283 
284 
285 
286 
287