File Source: SharedThemeFromDir.java
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. The ASF licenses this file to You
4 * under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License. For additional information regarding
15 * copyright in this work, please see the NOTICE file in the top level
16 * directory of this distribution.
17 */
18
19 package org.apache.roller.weblogger.business.themes;
20
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.Date;
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32 import org.apache.commons.lang.StringUtils;
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.roller.weblogger.pojos.ThemeResource;
36 import org.apache.roller.weblogger.pojos.ThemeTemplate;
37 import org.apache.roller.weblogger.pojos.WeblogTemplate;
38
39
40 /**
41 * The Theme object encapsulates all elements of a single weblog theme. It
42 * is used mostly to contain all the templates for a theme, but does contain
43 * other theme related attributes such as name, last modifed date, etc.
44 */
45 public class SharedThemeFromDir extends SharedTheme {
46
/*
P/P * Method: org.apache.roller.weblogger.business.themes.SharedThemeFromDir__static_init
*
* Postconditions:
* init'ed(log)
*/
47 private static Log log = LogFactory.getLog(SharedThemeFromDir.class);
48
49 // the filesystem directory where we should read this theme from
50 private String themeDir = null;
51
52 // the theme preview image
53 private ThemeResource previewImage = null;
54
55 // the theme stylesheet
56 private ThemeTemplate stylesheet = null;
57
58 // we keep templates in a Map for faster lookups by name
59 // the Map contains ... (template name, ThemeTemplate)
60 private Map templatesByName = new HashMap();
61
62 // we keep templates in a Map for faster lookups by link
63 // the Map contains ... (template link, ThemeTemplate)
64 private Map templatesByLink = new HashMap();
65
66 // we keep templates in a Map for faster lookups by action
67 // the Map contains ... (template action, ThemeTemplate)
68 private Map templatesByAction = new HashMap();
69
70 // we keep resources in a Map for faster lookups by path
71 // the Map contains ... (resource path, ThemeResource)
72 private Map resources = new HashMap();
73
74
75 public SharedThemeFromDir(String themeDirPath)
/*
P/P * Method: void org.apache.roller.weblogger.business.themes.SharedThemeFromDir(String)
*
* Preconditions:
* log != null
*
* Postconditions:
* java.lang.StringBuilder:toString(...)._tainted == 0
* init'ed(this.author)
* init'ed(this.description)
* this.enabled == 1
* init'ed(this.id)
* this.lastModified == &new Date(loadThemeFromDisk#8)
* init'ed(this.name)
* this.previewImage == One-of{null, &new SharedThemeResourceFromDir(loadThemeFromDisk#12)}
* this.previewImage in Addr_Set{null,&new SharedThemeResourceFromDir(loadThemeFromDisk#12)}
* this.resources == &new HashMap(SharedThemeFromDir#4)
* ...
*/
76 throws ThemeInitializationException {
77
78 this.themeDir = themeDirPath;
79
80 // load the theme elements and cache 'em
81 loadThemeFromDisk();
82 }
83
84
85 /**
86 * Get a resource representing the preview image for this theme.
87 */
88 public ThemeResource getPreviewImage() {
/*
P/P * Method: ThemeResource getPreviewImage()
*
* Preconditions:
* init'ed(this.previewImage)
*
* Postconditions:
* return_value == this.previewImage
* init'ed(return_value)
*/
89 return this.previewImage;
90 }
91
92
93 /**
94 * Get the collection of all templates associated with this Theme.
95 */
96 public List getTemplates() {
/*
P/P * Method: List getTemplates()
*
* Preconditions:
* this.templatesByName != null
*
* Postconditions:
* return_value == &new ArrayList(getTemplates#1)
* new ArrayList(getTemplates#1) num objects == 1
*/
97 return new ArrayList(this.templatesByName.values());
98 }
99
100
101 /**
102 * Lookup the stylesheet.
103 * Returns null if no stylesheet defined.
104 */
105 public ThemeTemplate getStylesheet() {
/*
P/P * Method: ThemeTemplate getStylesheet()
*
* Preconditions:
* init'ed(this.stylesheet)
*
* Postconditions:
* return_value == this.stylesheet
* init'ed(return_value)
*/
106 return this.stylesheet;
107 }
108
109
110 /**
111 * Looup the default template, action = weblog.
112 * Returns null if the template cannot be found.
113 */
114 public ThemeTemplate getDefaultTemplate() {
/*
P/P * Method: ThemeTemplate getDefaultTemplate()
*
* Preconditions:
* this.templatesByAction != null
*
* Postconditions:
* init'ed(return_value)
*/
115 return (ThemeTemplate) this.templatesByAction.get(ThemeTemplate.ACTION_WEBLOG);
116 }
117
118
119 /**
120 * Lookup the specified template by name.
121 * Returns null if the template cannot be found.
122 */
123 public ThemeTemplate getTemplateByName(String name) {
/*
P/P * Method: ThemeTemplate getTemplateByName(String)
*
* Preconditions:
* this.templatesByName != null
*
* Postconditions:
* init'ed(return_value)
*/
124 return (ThemeTemplate) this.templatesByName.get(name);
125 }
126
127
128 /**
129 * Lookup the specified template by link.
130 * Returns null if the template cannot be found.
131 */
132 public ThemeTemplate getTemplateByLink(String link) {
/*
P/P * Method: ThemeTemplate getTemplateByLink(String)
*
* Preconditions:
* this.templatesByLink != null
*
* Postconditions:
* init'ed(return_value)
*/
133 return (ThemeTemplate) this.templatesByLink.get(link);
134 }
135
136
137 /**
138 * Lookup the specified template by action.
139 * Returns null if the template cannot be found.
140 */
141 public ThemeTemplate getTemplateByAction(String action) {
/*
P/P * Method: ThemeTemplate getTemplateByAction(String)
*
* Preconditions:
* this.templatesByAction != null
*
* Postconditions:
* init'ed(return_value)
*/
142 return (ThemeTemplate) this.templatesByAction.get(action);
143 }
144
145
146 /**
147 * Get the collection of all resources associated with this Theme.
148 *
149 * It is assured that the resources are returned sorted by pathname.
150 */
151 public List getResources() {
152
153 // make sure resources are sorted.
/*
P/P * Method: List getResources()
*
* Preconditions:
* this.resources != null
*
* Postconditions:
* return_value == &new ArrayList(getResources#1)
* new ArrayList(getResources#1) num objects == 1
*/
154 List myResources = new ArrayList(this.resources.values());
155 Collections.sort(myResources);
156
157 return myResources;
158 }
159
160
161 /**
162 * Lookup the specified resource by path.
163 * Returns null if the resource cannot be found.
164 */
165 public ThemeResource getResource(String path) {
/*
P/P * Method: ThemeResource getResource(String)
*
* Preconditions:
* this.resources != null
*
* Postconditions:
* init'ed(return_value)
*/
166 return (ThemeResource) this.resources.get(path);
167 }
168
169
170 public String toString() {
/*
P/P * Method: String toString()
*
* Preconditions:
* init'ed(this.name)
* this.templatesByName != null
*
* Presumptions:
* java.util.Map:values(...)@175 != null
*
* Postconditions:
* init'ed(java.lang.StringBuffer:toString(...)._tainted)
* return_value == &java.lang.StringBuffer:toString(...)
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@176: {0}, {1}
*/
171 StringBuffer sb = new StringBuffer();
172 sb.append(name);
173 sb.append("\n");
174
175 Iterator it = this.templatesByName.values().iterator();
176 while(it.hasNext()) {
177 sb.append(it.next());
178 sb.append("\n");
179 }
180
181 return sb.toString();
182
183 }
184
185
186 /**
187 * Load all the elements of this theme from disk and cache them.
188 */
189 private void loadThemeFromDisk() throws ThemeInitializationException {
190
/*
P/P * Method: void loadThemeFromDisk()
*
* Preconditions:
* log != null
* init'ed(this.themeDir)
* (soft) this.resources != null
* (soft) this.templatesByAction != null
* (soft) this.templatesByLink != null
* (soft) this.templatesByName != null
*
* Presumptions:
* init'ed(java.io.File.separator)
* java.util.Iterator:next(...)@283 != null
*
* Postconditions:
* java.lang.StringBuilder:toString(...)._tainted == 0
* init'ed(this.author)
* init'ed(this.description)
* this.enabled == 1
* init'ed(this.id)
* this.lastModified == &new Date(loadThemeFromDisk#8)
* init'ed(this.name)
* this.previewImage == One-of{old this.previewImage, &new SharedThemeResourceFromDir(loadThemeFromDisk#12)}
* this.stylesheet == One-of{old this.stylesheet, &new SharedThemeTemplate(loadThemeFromDisk#16)}
* new Date(loadThemeFromDisk#18) num objects <= 1
* ...
*
* Test Vectors:
* java.io.File:canRead(...)@215: {1}, {0}
* java.io.File:canRead(...)@269: {1}, {0}
* java.io.File:exists(...)@215: {0}, {1}
* java.io.File:exists(...)@269: {0}, {1}
* java.util.Iterator:hasNext(...)@262: {0}, {1}
* java.util.Iterator:hasNext(...)@282: {0}, {1}
*/
191 log.debug("Parsing theme descriptor for "+this.themeDir);
192
193 ThemeMetadata themeMetadata = null;
194 try {
195 // lookup theme descriptor and parse it
196 ThemeMetadataParser parser = new ThemeMetadataParser();
197 InputStream is = new FileInputStream(this.themeDir + File.separator + "theme.xml");
198 themeMetadata = parser.unmarshall(is);
199 } catch (Exception ex) {
200 throw new ThemeInitializationException("Unable to parse theme descriptor for theme "+this.themeDir, ex);
201 }
202
203 log.debug("Loading Theme "+themeMetadata.getName());
204
205 // use parsed theme descriptor to load Theme data
206 setId(themeMetadata.getId());
207 setName(themeMetadata.getName());
208 setDescription(themeMetadata.getName());
209 setAuthor(themeMetadata.getAuthor());
210 setLastModified(new Date());
211 setEnabled(true);
212
213 // load resource representing preview image
214 File previewFile = new File(this.themeDir + File.separator + themeMetadata.getPreviewImage());
215 if(!previewFile.exists() || !previewFile.canRead()) {
216 log.warn("Couldn't read theme [" + this.getName() + "] preview image file ["+themeMetadata.getPreviewImage()+"]");
217 } else {
218 this.previewImage = new SharedThemeResourceFromDir(themeMetadata.getPreviewImage(), previewFile);
219 }
220
221 // load stylesheet if possible
222 if(themeMetadata.getStylesheet() != null) {
223
224 ThemeMetadataTemplate stylesheetTmpl = themeMetadata.getStylesheet();
225
226 // construct File object from path
227 File templateFile = new File(this.themeDir + File.separator +
228 stylesheetTmpl.getContentsFile());
229
230 // read stylesheet contents
231 String contents = loadTemplateFile(templateFile);
232 if(contents == null) {
233 // if we don't have any contents then skip this one
234 log.error("Couldn't load stylesheet theme [" + this.getName() + "] template file ["+templateFile+"]");
235 } else {
236
237 // construct ThemeTemplate representing this file
238 SharedThemeTemplate theme_template = new SharedThemeTemplate(
239 this,
240 themeMetadata.getId()+":"+stylesheetTmpl.getName(),
241 WeblogTemplate.ACTION_CUSTOM,
242 stylesheetTmpl.getName(),
243 stylesheetTmpl.getDescription(),
244 contents,
245 stylesheetTmpl.getLink(),
246 new Date(templateFile.lastModified()),
247 stylesheetTmpl.getTemplateLanguage(),
248 false,
249 false);
250
251 // store it
252 this.stylesheet = theme_template;
253
254 // add it to templates list
255 addTemplate(theme_template);
256 }
257 }
258
259 // go through static resources and add them to the theme
260 String resourcePath = null;
261 Iterator resourcesIter = themeMetadata.getResources().iterator();
262 while (resourcesIter.hasNext()) {
263 resourcePath = (String) resourcesIter.next();
264
265 // construct ThemeResource object from resource
266 File resourceFile = new File(this.themeDir + File.separator + resourcePath);
267
268 // Continue reading theme even if problem encountered with one file
269 if(!resourceFile.exists() || !resourceFile.canRead()) {
270 log.warn("Couldn't read theme [" + this.getName() + "] resource file ["+resourcePath+"]");
271 continue;
272 }
273
274 // add it to the theme
275 setResource(resourcePath, new SharedThemeResourceFromDir(resourcePath, resourceFile));
276 }
277
278 // go through templates and read in contents to a ThemeTemplate
279 ThemeTemplate theme_template = null;
280 ThemeMetadataTemplate templateMetadata = null;
281 Iterator templatesIter = themeMetadata.getTemplates().iterator();
282 while (templatesIter.hasNext()) {
283 templateMetadata = (ThemeMetadataTemplate) templatesIter.next();
284
285 // construct File object from path
286 File templateFile = new File(this.themeDir + File.separator +
287 templateMetadata.getContentsFile());
288
289 String contents = loadTemplateFile(templateFile);
290 if(contents == null) {
291 // if we don't have any contents then skip this one
+ 292 throw new ThemeInitializationException("Couldn't load theme [" + this.getName() + "] template file ["+templateFile+"]");
293 }
294
295 // construct ThemeTemplate representing this file
296 theme_template = new SharedThemeTemplate(
297 this,
298 themeMetadata.getId()+":"+templateMetadata.getName(),
299 templateMetadata.getAction(),
300 templateMetadata.getName(),
301 templateMetadata.getDescription(),
302 contents,
303 templateMetadata.getLink(),
304 new Date(templateFile.lastModified()),
305 templateMetadata.getTemplateLanguage(),
306 templateMetadata.isHidden(),
307 templateMetadata.isNavbar());
308
309 // add it to the theme
310 addTemplate(theme_template);
311 }
312 }
313
314
315 /**
316 * Load a single template file as a string, returns null if can't read file.
317 */
318 private String loadTemplateFile(File templateFile) {
319 // Continue reading theme even if problem encountered with one file
/*
P/P * Method: String loadTemplateFile(File)
*
* Preconditions:
* templateFile != null
* (soft) log != null
* (soft) init'ed(this.name)
*
* Presumptions:
* java.io.File:length(...)@327 >= 0
*
* Postconditions:
* return_value in Addr_Set{null,&new String(loadTemplateFile#5)}
* new String(loadTemplateFile#5) num objects <= 1
*
* Test Vectors:
* java.io.File:canRead(...)@320: {1}, {0}
* java.io.File:exists(...)@320: {1}, {0}
*/
320 if(!templateFile.exists() && !templateFile.canRead()) {
321 return null;
322 }
323
324 char[] chars = null;
325 int length;
326 try {
327 chars = new char[(int) templateFile.length()];
328 FileInputStream stream = new FileInputStream(templateFile);
329 InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
330 length = reader.read(chars);
331 } catch (Exception noprob) {
332 log.error("Exception reading theme [" + this.getName() + "] template file ["+templateFile+"]");
333 if (log.isDebugEnabled())
334 log.debug(noprob);
335 return null;
336 }
337
338 return new String(chars, 0, length);
339 }
340
341
342 /**
343 * Set the value for a given template name.
344 */
345 private void addTemplate(ThemeTemplate template) {
/*
P/P * Method: void addTemplate(ThemeTemplate)
*
* Preconditions:
* template != null
* this.templatesByLink != null
* this.templatesByName != null
* (soft) this.templatesByAction != null
*
* Test Vectors:
* java.lang.String:equals(...)@348: {1}, {0}
*/
346 this.templatesByName.put(template.getName(), template);
347 this.templatesByLink.put(template.getLink(), template);
348 if(!ThemeTemplate.ACTION_CUSTOM.equals(template.getAction())) {
349 this.templatesByAction.put(template.getAction(), template);
350 }
351 }
352
353
354 /**
355 * Set the value for a given resource path.
356 */
357 private void setResource(String path, SharedThemeResourceFromDir resource) {
358 // normalize to use web-style separators
/*
P/P * Method: void setResource(String, SharedThemeResourceFromDir)
*
* Preconditions:
* this.resources != null
*/
359 String normalizedPath = StringUtils.replace(path, "\\", "/");
360 this.resources.put(normalizedPath, resource);
361 }
362
363 }
SofCheck Inspector Build Version : 2.18479
| SharedThemeFromDir.java |
2009-Jan-02 14:25:48 |
| SharedThemeFromDir.class |
2009-Sep-04 03:12:31 |