View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.jetspeed.locator;
18  
19  import java.io.File;
20  import java.io.FileNotFoundException;
21  import java.util.Collections;
22  import java.util.HashMap;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.StringTokenizer;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  /***
32   * Jetspeed's default implementation of a template locator.
33   *
34   * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
35   * @version $Id: JetspeedTemplateLocator.java 553014 2007-07-03 23:10:53Z ate $
36   */
37  public class JetspeedTemplateLocator implements TemplateLocator
38  {
39      private final static Log log = LogFactory.getLog(JetspeedTemplateLocator.class);
40  
41      private static final String PATH_SEPARATOR = "/";
42  
43      /*** the template root directories, all application root relative */
44      private List roots;
45      
46      /*** Root of the application running this locator */
47      private String appRoot;
48         
49      /*** the Template class is factory created */     
50      private Class  templateClass = JetspeedTemplateDescriptor.class;
51  
52      /*** the TemplateLocator class is factory created */     
53      private Class  locatorClass = JetspeedLocatorDescriptor.class;
54      
55      /*** the default locator type */
56      private String defaultLocatorType = "layout";
57  
58      /*** template name cache used to speed up searches for templates */
59      private Map templateMap = null;
60  
61      /*** use the name cache when looking up a template */
62      private boolean useNameCache = true;
63  
64      private JetspeedTemplateLocator()
65      {
66          // need to know roots
67      }
68      
69      /***
70       * Minimal assembly with a list of resource directory roots.
71       * 
72       * @param roots A list of resource root directories where templates are located.
73       * @param appRoot  Root from where this application runs
74       */
75      public JetspeedTemplateLocator(List roots, String appRoot) throws FileNotFoundException 
76      {
77          this.appRoot = appRoot;
78          log.info("Locator application root "+new File(appRoot).getAbsolutePath());
79          this.roots = roots;   
80          Iterator itr = roots.iterator();
81          while(itr.hasNext())
82          {
83              String path  = (String) itr.next();
84              File checkFile = new File(path);
85              if(!checkFile.exists())
86              {
87                  throw new FileNotFoundException("Locator resource root "+checkFile.getAbsolutePath()+" does not exist.");
88              }
89          }        
90      }
91  
92      /***
93       * Construct with a root list and a default locator type.
94       * 
95       * @param roots A list of resource root directories where templates are located.
96       * @param defaultLocatorType Under root directories, subdirectories represent locator types.
97       *                           A locator type represents a classification of templates.
98       *                           Any value is allowed. Use locator types to group templates together. 
99       */
100     public JetspeedTemplateLocator(List roots, 
101                                         String defaultLocatorType,
102                                         String appRoot) throws FileNotFoundException
103     {
104         this(roots, appRoot);
105         this.defaultLocatorType = defaultLocatorType;
106     }
107 
108     /***
109      * Assemble with list resource directory roots and OM classes and a defaultLocatorType.
110      * 
111      * @param roots A list of resource root directories where templates are located.
112      * @param omClasses Template replacable object model implementations for Template and TemplateLocator.
113      *                  Required order, with second optional: [ <code>Template</code>, <code>TemplateLocator</code> implementations. 
114      * @param defaultLocatorType Under root directories, subdirectories represent locator types.
115      *                           A locator type represents a classification of templates.
116      *                           Any value is allowed. Use locator types to group templates together. 
117      */
118     public JetspeedTemplateLocator(List roots, 
119                                    List omClasses,
120                                    String defaultLocatorType,
121                                    String appRoot) throws FileNotFoundException
122     {
123         this(roots,  defaultLocatorType, appRoot);                
124       
125         if (omClasses.size() > 0)
126         {
127             this.templateClass = (Class)omClasses.get(0);
128             if (omClasses.size() > 1)
129             {
130                 this.locatorClass  = (Class)omClasses.get(1);
131             }
132         }        
133     }
134     
135     public TemplateDescriptor locateTemplate(LocatorDescriptor locator)
136     {
137         for (int ix = 0; ix < roots.size(); ix++)
138         {        
139             TemplateDescriptor template = locateTemplate(locator, (String)roots.get(ix));
140             if (null == template)
141             {
142                 // Try to locate it directly on file system, perhaps it was recently added
143                 useNameCache = false;
144                 template = locateTemplate(locator, (String)roots.get(ix));
145                 if (null != template)
146                 {
147                     // add it to the map
148                     templateMap.put(template.getAbsolutePath(), null);
149                 }
150                 useNameCache = true;   
151             }
152             if (template != null)
153             {
154                 return template;
155             }
156         }
157         return null;        
158     }
159  
160     /***
161      * General template location algorithm. Starts with the most specific resource,
162      * including mediatype + nls specification, and fallsback to least specific.
163      *
164      * @param locator The template locator 
165      * @param root The root directory to search
166      *
167      * @return TemplateDescriptor the exact path to the template, or null if not found.
168      */
169     private TemplateDescriptor locateTemplate(LocatorDescriptor locator, String root)
170     {
171         String templateName = locator.getName();       
172         String path = locator.toPath();
173                 
174         String realPath = null;
175         String workingPath = null;
176 
177         int lastSeperator;
178         while (path !=null && (lastSeperator = path.lastIndexOf(PATH_SEPARATOR))> 0)
179         {
180             path = path.substring(0, lastSeperator);
181 
182             workingPath = path + PATH_SEPARATOR + templateName;
183             realPath = root + workingPath;
184 
185             // the current template exists, return the corresponding path
186             if (templateExists(realPath))
187             {
188                 if (log.isDebugEnabled())
189                 {
190                     log.debug(
191                             "TemplateLocator: template exists: "
192                                 + realPath
193                                 + " returning "
194                                 + workingPath);
195                 }
196                 int appRootLength = appRoot.length();
197                 // remove the application root path from the reall path to
198                 // give us a app relative path
199                 String appRelativePath = realPath.substring(appRootLength, realPath.length());
200                 // return createTemplateFromPath(path, templateName, realPath, "/WEB-INF/templates" + workingPath);
201                 return createTemplateFromPath(path, templateName, realPath, appRelativePath);
202             }
203         }
204         return null;
205     }
206 
207     /***
208      * Checks for the existence of a template resource given a key.
209      * The key are absolute paths to the templates, and are cached
210      * in a template cache for performance.
211      *
212      * @param key The absolute path to the template resource.
213      *
214      * @return True when the template is found, otherwise false.
215      */
216     public boolean templateExists(String templateKey)
217     {
218         if (null == templateKey)
219         {
220             return false;
221         }
222         if (useNameCache == true)
223         {
224             return templateMap.containsKey(templateKey);
225         }
226         return (new File(templateKey).exists());
227     }
228     
229    
230     public LocatorDescriptor createFromString(String path)
231         throws TemplateLocatorException
232     {
233         LocatorDescriptor locator = createLocatorDescriptor(this.defaultLocatorType);
234         StringTokenizer tok = new StringTokenizer(path, "/");
235         while (tok.hasMoreTokens())
236         {
237             String name = tok.nextToken();
238             if (name.equals(LocatorDescriptor.PARAM_TYPE) && tok.hasMoreTokens())
239             {
240                 locator.setType( tok.nextToken() );
241             }
242             else if (name.equals(LocatorDescriptor.PARAM_MEDIA_TYPE) && tok.hasMoreTokens())
243             {
244                 locator.setMediaType(tok.nextToken());
245             }
246             else if (name.equals(LocatorDescriptor.PARAM_LANGUAGE) && tok.hasMoreTokens())
247             {
248                 locator.setLanguage(tok.nextToken());
249             }
250             else if (name.equals(LocatorDescriptor.PARAM_COUNTRY) && tok.hasMoreTokens())
251             {
252                 locator.setCountry(tok.nextToken());
253             }
254         
255             else if (name.equals(LocatorDescriptor.PARAM_NAME) && tok.hasMoreTokens())
256             {
257                 locator.setName(tok.nextToken());
258             }
259         }    
260         return locator;    
261     }
262 
263     /***
264      * Given a path, name and realPath creates a new template object
265      * 
266      * @param path the relative path to the template
267      * @param name the template name
268      * @param realPath the real path on the file system
269      * @return newly created TemplateDescriptor
270      */
271     private TemplateDescriptor createTemplateFromPath(String path, String name, String realPath, String relativePath)
272     {    
273         TemplateDescriptor template = this.createTemplate();
274         template.setAbsolutePath(realPath);
275         if(relativePath.indexOf("/") != 0)
276         {
277             relativePath = "/"+relativePath;
278         }
279         template.setAppRelativePath(relativePath);
280         template.setName(name);            
281         StringTokenizer tok = new StringTokenizer(path, "/");
282         int count = 0;
283         while (tok.hasMoreTokens())
284         {
285             String token = tok.nextToken();
286             switch (count)
287             {
288                 case 0:
289                     template.setType(token);
290                     break;
291                 case 1:
292                     template.setMediaType(token);
293                     break;
294                 case 2:
295                     template.setLanguage(token);
296                     break;
297                 case 3:                    
298                     template.setCountry(token);
299                     break;                                    
300             }
301             count++;
302         }    
303         return template;                                                    
304     }
305     
306     public LocatorDescriptor createLocatorDescriptor(String type)
307         throws TemplateLocatorException
308     {
309         LocatorDescriptor locator = null;
310             
311         try
312         {
313             locator = (LocatorDescriptor)locatorClass.newInstance();
314             locator.setType(type);
315         }
316         catch(Exception e)
317         {
318             throw new TemplateLocatorException("Failed instantiate a Template Locator implementation object: ", e);
319         }
320         return locator;    
321     }
322 
323     private TemplateDescriptor createTemplate()
324     {
325         TemplateDescriptor template = null;
326             
327         try
328         {
329             template = (TemplateDescriptor)templateClass.newInstance();
330         }
331         catch(Exception e)
332         {
333             log.error("Failed to create template", e);
334             template = new JetspeedTemplateDescriptor();            
335         }
336         return template;    
337     }
338 
339     public void start()
340     {        
341         this.templateMap = Collections.synchronizedMap(new HashMap());
342 
343         for (int ix = 0; ix < roots.size(); ix++)
344         {
345             String templateRoot = (String)roots.get(ix);
346 
347             if (!templateRoot.endsWith(PATH_SEPARATOR))
348             {
349                 templateRoot = templateRoot + PATH_SEPARATOR;
350             }
351 
352             loadNameCache(templateRoot, "");
353         }
354     }
355 
356     public void stop()
357     {
358     }
359   
360     public Iterator query(LocatorDescriptor locator)
361     {
362         return null; // TODO: implement this
363     }
364 
365     /***
366      * Loads the template name cache map to accelerate template searches.
367      *
368      * @param path The template
369      * @param name just the name of the resource
370      */
371     private void loadNameCache(String path, String name)
372     {
373         File file = new File(path);
374         if (file.isFile())
375         {
376             // add it to the map
377             templateMap.put(path, null);
378         }
379         else
380         {
381             if (file.isDirectory())
382             {
383                 if (!path.endsWith(File.separator))
384                 {
385                     path += File.separator;
386                 }
387 
388                 String list[] = file.list();
389 
390                 // Process all files recursivly
391                 for (int ix = 0; list != null && ix < list.length; ix++)
392                 {
393                     loadNameCache(path + list[ix], list[ix]);
394                 }
395             }
396         }
397     }
398 }