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 587334 2007-10-23 00:30:49Z taylor $
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), this.useNameCache);
140             if (null == template)
141             {
142                 // Try to locate it directly on file system, perhaps it was recently added
143                 template = locateTemplate(locator, (String)roots.get(ix), false);
144                 if (null != template)
145                 {
146                     // add it to the map
147                     templateMap.put(template.getAbsolutePath(), null);
148                 }
149             }
150             if (template != null)
151             {
152                 return template;
153             }
154         }
155         return null;        
156     }
157  
158     /***
159      * General template location algorithm. Starts with the most specific resource,
160      * including mediatype + nls specification, and fallsback to least specific.
161      *
162      * @param locator The template locator 
163      * @param root The root directory to search
164      *
165      * @return TemplateDescriptor the exact path to the template, or null if not found.
166      */
167     private TemplateDescriptor locateTemplate(LocatorDescriptor locator, String root, boolean useCache)
168     {
169         String templateName = locator.getName();       
170         String path = locator.toPath();
171                 
172         String realPath = null;
173         String workingPath = null;
174 
175         int lastSeperator;
176         while (path !=null && (lastSeperator = path.lastIndexOf(PATH_SEPARATOR))> 0)
177         {
178             path = path.substring(0, lastSeperator);
179 
180             workingPath = path + PATH_SEPARATOR + templateName;
181             realPath = root + workingPath;
182 
183             // the current template exists, return the corresponding path
184             if (templateExists(realPath, useCache))
185             {
186                 if (log.isDebugEnabled())
187                 {
188                     log.debug(
189                             "TemplateLocator: template exists: "
190                                 + realPath
191                                 + " returning "
192                                 + workingPath);
193                 }
194                 int appRootLength = appRoot.length();
195                 // remove the application root path from the reall path to
196                 // give us a app relative path
197                 String appRelativePath = realPath.substring(appRootLength, realPath.length());
198                 // return createTemplateFromPath(path, templateName, realPath, "/WEB-INF/templates" + workingPath);
199                 return createTemplateFromPath(path, templateName, realPath, appRelativePath);
200             }
201         }
202         return null;
203     }
204 
205     /***
206      * Checks for the existence of a template resource given a key.
207      * The key are absolute paths to the templates, and are cached
208      * in a template cache for performance.
209      *
210      * @param key The absolute path to the template resource.
211      *
212      * @return True when the template is found, otherwise false.
213      */
214     public boolean templateExists(String templateKey, boolean useCache)
215     {
216         if (null == templateKey)
217         {
218             return false;
219         }
220         if (useCache == true)
221         {
222             return templateMap.containsKey(templateKey);
223         }
224         return (new File(templateKey).exists());
225     }
226 
227     public boolean templateExists(String templateKey)
228     {
229         return templateExists(templateKey, this.useNameCache);
230     }
231    
232     public LocatorDescriptor createFromString(String path)
233         throws TemplateLocatorException
234     {
235         LocatorDescriptor locator = createLocatorDescriptor(this.defaultLocatorType);
236         StringTokenizer tok = new StringTokenizer(path, "/");
237         while (tok.hasMoreTokens())
238         {
239             String name = tok.nextToken();
240             if (name.equals(LocatorDescriptor.PARAM_TYPE) && tok.hasMoreTokens())
241             {
242                 locator.setType( tok.nextToken() );
243             }
244             else if (name.equals(LocatorDescriptor.PARAM_MEDIA_TYPE) && tok.hasMoreTokens())
245             {
246                 locator.setMediaType(tok.nextToken());
247             }
248             else if (name.equals(LocatorDescriptor.PARAM_LANGUAGE) && tok.hasMoreTokens())
249             {
250                 locator.setLanguage(tok.nextToken());
251             }
252             else if (name.equals(LocatorDescriptor.PARAM_COUNTRY) && tok.hasMoreTokens())
253             {
254                 locator.setCountry(tok.nextToken());
255             }
256         
257             else if (name.equals(LocatorDescriptor.PARAM_NAME) && tok.hasMoreTokens())
258             {
259                 locator.setName(tok.nextToken());
260             }
261         }    
262         return locator;    
263     }
264 
265     /***
266      * Given a path, name and realPath creates a new template object
267      * 
268      * @param path the relative path to the template
269      * @param name the template name
270      * @param realPath the real path on the file system
271      * @return newly created TemplateDescriptor
272      */
273     private TemplateDescriptor createTemplateFromPath(String path, String name, String realPath, String relativePath)
274     {    
275         TemplateDescriptor template = this.createTemplate();
276         template.setAbsolutePath(realPath);
277         if(relativePath.indexOf("/") != 0)
278         {
279             relativePath = "/"+relativePath;
280         }
281         template.setAppRelativePath(relativePath);
282         template.setName(name);            
283         StringTokenizer tok = new StringTokenizer(path, "/");
284         int count = 0;
285         while (tok.hasMoreTokens())
286         {
287             String token = tok.nextToken();
288             switch (count)
289             {
290                 case 0:
291                     template.setType(token);
292                     break;
293                 case 1:
294                     template.setMediaType(token);
295                     break;
296                 case 2:
297                     template.setLanguage(token);
298                     break;
299                 case 3:                    
300                     template.setCountry(token);
301                     break;                                    
302             }
303             count++;
304         }    
305         return template;                                                    
306     }
307     
308     public LocatorDescriptor createLocatorDescriptor(String type)
309         throws TemplateLocatorException
310     {
311         LocatorDescriptor locator = null;
312             
313         try
314         {
315             locator = (LocatorDescriptor)locatorClass.newInstance();
316             locator.setType(type);
317         }
318         catch(Exception e)
319         {
320             throw new TemplateLocatorException("Failed instantiate a Template Locator implementation object: ", e);
321         }
322         return locator;    
323     }
324 
325     private TemplateDescriptor createTemplate()
326     {
327         TemplateDescriptor template = null;
328             
329         try
330         {
331             template = (TemplateDescriptor)templateClass.newInstance();
332         }
333         catch(Exception e)
334         {
335             log.error("Failed to create template", e);
336             template = new JetspeedTemplateDescriptor();            
337         }
338         return template;    
339     }
340 
341     public void start()
342     {        
343         this.templateMap = Collections.synchronizedMap(new HashMap());
344 
345         for (int ix = 0; ix < roots.size(); ix++)
346         {
347             String templateRoot = (String)roots.get(ix);
348 
349             if (!templateRoot.endsWith(PATH_SEPARATOR))
350             {
351                 templateRoot = templateRoot + PATH_SEPARATOR;
352             }
353 
354             loadNameCache(templateRoot, "");
355         }
356     }
357 
358     public void stop()
359     {
360     }
361   
362     public Iterator query(LocatorDescriptor locator)
363     {
364         return null; // TODO: implement this
365     }
366 
367     /***
368      * Loads the template name cache map to accelerate template searches.
369      *
370      * @param path The template
371      * @param name just the name of the resource
372      */
373     private void loadNameCache(String path, String name)
374     {
375         File file = new File(path);
376         if (file.isFile())
377         {
378             // add it to the map
379             templateMap.put(path, null);
380         }
381         else
382         {
383             if (file.isDirectory())
384             {
385                 if (!path.endsWith(File.separator))
386                 {
387                     path += File.separator;
388                 }
389 
390                 String list[] = file.list();
391 
392                 // Process all files recursivly
393                 for (int ix = 0; list != null && ix < list.length; ix++)
394                 {
395                     loadNameCache(path + list[ix], list[ix]);
396                 }
397             }
398         }
399     }
400 }