1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
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
143 template = locateTemplate(locator, (String)roots.get(ix), false);
144 if (null != template)
145 {
146
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
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
196
197 String appRelativePath = realPath.substring(appRootLength, realPath.length());
198
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;
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
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
393 for (int ix = 0; list != null && ix < list.length; ix++)
394 {
395 loadNameCache(path + list[ix], list[ix]);
396 }
397 }
398 }
399 }
400 }