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 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
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
143 useNameCache = false;
144 template = locateTemplate(locator, (String)roots.get(ix));
145 if (null != template)
146 {
147
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
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
198
199 String appRelativePath = realPath.substring(appRootLength, realPath.length());
200
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;
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
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
391 for (int ix = 0; list != null && ix < list.length; ix++)
392 {
393 loadNameCache(path + list[ix], list[ix]);
394 }
395 }
396 }
397 }
398 }