View Javadoc

1   /*
2    * $Source: /usr/cvsroot/melati/melati/src/main/java/org/melati/template/ClassNameTempletLoader.java,v $
3    * $Revision: 1.42 $
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.util.Hashtable;
49  
50  import org.melati.poem.FieldAttributes;
51  import org.melati.util.MelatiBugMelatiException;
52  
53  /**
54   * Load a template to render an object based upon the object's class.
55   */
56  public final class ClassNameTempletLoader implements TempletLoader {
57  
58    /** The instance. */
59    private static ClassNameTempletLoader it = null;
60  
61    // NOTE It is not expected that templates will be added at runtime.
62    private static Hashtable<String,Template> templetForClassCache = new Hashtable<String,Template>();
63    
64    private static final Integer FOUND = new Integer(1);
65    private static final Integer NOT_FOUND = new Integer(0);
66    private static Hashtable<String,Integer> lookedupTemplateNames = new Hashtable<String,Integer>();
67  
68    /** Disable instantiation. */
69    private ClassNameTempletLoader() {}
70  
71    /**
72     * @return the instance
73     */
74    public static ClassNameTempletLoader getInstance() {
75      if (it == null)
76        it = new ClassNameTempletLoader();
77      return it;
78    }
79    protected static String templetsPath(TemplateEngine templateEngine, 
80                                  MarkupLanguage markupLanguage) {
81      /*
82      // Fails to find templates in jars!!
83      return "org" + File.separatorChar + 
84             "melati" + File.separatorChar + 
85             "template" + File.separatorChar + 
86              templateEngine.getName() + File.separatorChar + 
87             "templets" + File.separatorChar +
88              markupLanguage.getName() + File.separatorChar;
89      */
90      return "org/melati/templets/" + 
91             markupLanguage.getName() + "/";
92      
93      }
94  
95    /**
96     * @return the path in the templets directory
97     */
98    protected static String templetsTempletPath(TemplateEngine templateEngine,
99                                 MarkupLanguage markupLanguage,
100                                String purpose, String name) {
101     if (purpose == null)
102       return 
103                  templetsPath(templateEngine, markupLanguage) + 
104                  name +
105                  templateEngine.templateExtension();
106     return 
107                templetsPath(templateEngine, markupLanguage) + 
108                purpose + "/" + 
109                name +
110                templateEngine.templateExtension();
111   }
112 
113   protected static String classpathTempletPath(Class<?> clazz, TemplateEngine templateEngine) { 
114     return clazz.getName().replace('.', '/') + templateEngine.templateExtension();
115   }
116   /**
117    * Get a templet by name, with optional purpose. 
118    * 
119    * {@inheritDoc}
120    * @see TempletLoader#templet(TemplateEngine, AbstractMarkupLanguage, String, String)
121    */
122   public Template templet(TemplateEngine templateEngine,
123                           MarkupLanguage markupLanguage, String purpose,
124                           String name) throws NotFoundException {
125     return templateEngine.template(templetsTempletPath(templateEngine, markupLanguage,
126         purpose, name));
127   }
128 
129   /**
130    * Get a templet by its name, looking only in the templets directory.
131    * 
132    * {@inheritDoc}
133    * @see TempletLoader#templet(TemplateEngine, MarkupLanguage, String)
134    */
135   public Template templet(TemplateEngine templateEngine,
136                           MarkupLanguage markupLanguage, String name) 
137       throws NotFoundException {
138     return templet(templateEngine, markupLanguage, null, name);
139   }
140 
141   /**
142    * Get a templet based upon class name and optional purpose, 
143    * looking in the templets directory and also the classpath.
144    * 
145    * {@inheritDoc}
146    * @see TempletLoader#templet(TemplateEngine, MarkupLanguage, 
147    *                            String, Class)
148    */
149   public Template templet(TemplateEngine templateEngine,
150                           MarkupLanguage markupLanguage, String purpose,
151                           Class<?> clazz)
152       throws TemplateEngineException {
153     Class<?> lookupClass = clazz;
154     Template templet = null;
155     Template fromCache = null;
156     String originalCacheKey = cacheKey(templateEngine, markupLanguage, purpose, lookupClass);
157     String lookupCacheKey = originalCacheKey;
158     String lookupPurpose = purpose;
159     while (true) {
160       fromCache = (Template)templetForClassCache.get(lookupCacheKey);
161       if (fromCache != null) {
162         templet = fromCache;
163         break;
164       } 
165       //templet = getSpecialTemplate(lookupClass, lookupPurpose, markupLanguage, templateEngine);
166       //if (templet != null)
167       //  break;
168       
169       // Try to find one in the templets directory
170       String templetPath = templetsTempletPath(templateEngine, markupLanguage,
171               lookupPurpose, lookupClass.getName());
172       templet = getTemplate(templateEngine, templetPath);
173       if (templet != null)
174         break;
175       // Try to find one on classpath
176       templetPath = classpathTempletPath(lookupClass, templateEngine);
177       templet = getTemplate(templateEngine, templetPath);
178       if (templet != null)
179         break;
180       
181       if (lookupPurpose != null)
182         lookupPurpose = null;
183       else { 
184         lookupClass = lookupClass.getSuperclass();
185         lookupPurpose = purpose;
186       }
187       lookupCacheKey = cacheKey(templateEngine, markupLanguage, lookupPurpose, lookupClass);
188     }
189     // We should have at last found Object template    
190     //if (templet == null)
191     //  throw new MelatiBugMelatiException("Cannot even find template for Object");
192     System.err.println(lookupCacheKey);
193     if (fromCache == null)
194       templetForClassCache.put(originalCacheKey, templet);
195     if (!lookupCacheKey.equals(originalCacheKey)) { 
196       if (templetForClassCache.get(lookupCacheKey) == null) 
197         templetForClassCache.put(lookupCacheKey, templet);
198     } 
199     return templet;
200   }
201 
202   private String cacheKey(TemplateEngine templateEngine, 
203       MarkupLanguage markupLanguage, 
204       String purpose, 
205       Class<?> lookupClass) {
206     return  purpose == null ? cacheKey(templateEngine, markupLanguage, lookupClass) 
207                             : lookupClass + "/" + 
208                                purpose + "/" + 
209                                markupLanguage + "/" + 
210                                templateEngine.getName();
211   }
212   
213   private String cacheKey(TemplateEngine templateEngine, 
214       MarkupLanguage markupLanguage, 
215       Class<?> lookupClass) {
216     return lookupClass + 
217            "/" + markupLanguage + 
218            "/" + templateEngine.getName();
219   }
220 
221   private Template getTemplate(TemplateEngine templateEngine, String templetPath)  { 
222     Template templet = null;
223     try {
224       Object triedAlready = lookedupTemplateNames.get(templetPath);
225       if (triedAlready != NOT_FOUND) {
226         templet = templateEngine.template(templetPath);
227         lookedupTemplateNames.put(templetPath, FOUND);
228       } 
229     } catch (NotFoundException e) {
230       lookedupTemplateNames.put(templetPath, NOT_FOUND);
231     }
232     return templet;
233   }
234 
235   /**
236    * Get a templet for a class.
237    * 
238    * {@inheritDoc}
239    * @see TempletLoader#templet(TemplateEngine, MarkupLanguage, Class)
240    */
241   public Template templet(TemplateEngine templateEngine,
242                           MarkupLanguage markupLanguage, Class<?> clazz) {
243     return templet(templateEngine, markupLanguage, null, clazz);
244   }
245 
246   /**
247    * Get a templet either from the classname concatenated with 
248    * FieldAttributes.RenederInfo or the class name.
249    * 
250    * {@inheritDoc}
251    * @see TempletLoader#templet(TemplateEngine,MarkupLanguage,FieldAttributes)
252    */
253   public Template templet(TemplateEngine templateEngine,
254                           MarkupLanguage markupLanguage,
255                           FieldAttributes attributes) {
256     if (attributes.getRenderInfo() != null) {
257       String templetName = attributes.getType().getClass().getName() 
258           + "-"
259           + attributes.getRenderInfo();
260       try {
261         return templet(templateEngine, markupLanguage, 
262                 templetName);
263       } catch (NotFoundException e) {
264         throw new MelatiBugMelatiException(
265                 "Templet " + templetName  + " not found", e);
266       }
267     } else {
268         return templet(templateEngine, markupLanguage,
269                 attributes.getType().getClass());
270     }
271   }
272 }
273 
274 
275 
276 
277 
278 
279 
280 
281 
282