1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.theme.postprocessor;
17
18 import org.apache.commons.io.IOUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.apache.log4j.Logger;
21 import org.kuali.rice.krad.theme.util.ThemeBuilderConstants;
22 import org.kuali.rice.krad.theme.util.ThemeBuilderUtils;
23
24 import java.io.File;
25 import java.io.FileOutputStream;
26 import java.io.FileReader;
27 import java.io.IOException;
28 import java.io.InputStreamReader;
29 import java.io.OutputStream;
30 import java.io.OutputStreamWriter;
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Properties;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public abstract class ThemeFilesProcessor {
55 private static final Logger LOG = Logger.getLogger(ThemeFilesProcessor.class);
56
57 protected static final String PLUGIN_FILES_KEY = "plugin";
58 protected static final String SUBDIR_FILES_KEY = "subdir";
59
60 protected String themeName;
61 protected File themeDirectory;
62 protected Properties themeProperties;
63 protected Map<String, File> themePluginDirsMap;
64 protected File workingDir;
65 protected String projectVersion;
66
67 public ThemeFilesProcessor(String themeName, File themeDirectory, Properties themeProperties,
68 Map<String, File> themePluginDirsMap, File workingDir, String projectVersion) {
69 this.themeName = themeName;
70 this.themeDirectory = themeDirectory;
71 this.themeProperties = themeProperties;
72 this.themePluginDirsMap = themePluginDirsMap;
73 this.workingDir = workingDir;
74 this.projectVersion = projectVersion;
75 }
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97 public void process() {
98 Map<String, List<File>> themeFilesMap = collectThemeFiles();
99
100
101 List<File> themeFiles = sortThemeFiles(themeFilesMap.get(PLUGIN_FILES_KEY), themeFilesMap.get(
102 SUBDIR_FILES_KEY));
103
104 File mergedFile = createMergedFile(false);
105 try {
106 mergeFiles(themeFiles, mergedFile);
107 } catch (IOException e) {
108 throw new RuntimeException("Exception encountered while merging files for type: "
109 + getFileTypeExtension());
110 }
111
112 File minifiedFile = createMergedFile(true);
113 try {
114 minify(mergedFile, minifiedFile);
115 } catch (IOException e) {
116 throw new RuntimeException("Exception encountered while minifying files for type: "
117 + getFileTypeExtension());
118 }
119
120
121
122 List<String> themeFilePaths = ThemeBuilderUtils.getRelativePaths(this.workingDir, themeFiles);
123
124 this.themeProperties.put(getFileListingConfigKey(), StringUtils.join(themeFilePaths, ","));
125 }
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149 protected Map<String, List<File>> collectThemeFiles() {
150 Map<String, List<File>> themeFiles = new HashMap<String, List<File>>();
151
152 String[] fileIncludes = getFileIncludes();
153 String[] fileExcludes = getFileExcludes();
154
155
156 String[] pluginFileExcludes = null;
157 if (this.themeProperties.containsKey(ThemeBuilderConstants.ThemeConfiguration.PLUGIN_FILE_EXCLUDES)) {
158 pluginFileExcludes = ThemeBuilderUtils.getPropertyValueAsArray(
159 ThemeBuilderConstants.ThemeConfiguration.PLUGIN_FILE_EXCLUDES, this.themeProperties);
160 }
161
162
163 if (fileExcludes != null) {
164 if (pluginFileExcludes == null) {
165 pluginFileExcludes = fileExcludes;
166 } else {
167 pluginFileExcludes = ThemeBuilderUtils.addToArray(pluginFileExcludes, fileExcludes);
168 }
169 }
170
171
172
173 ThemeBuilderUtils.addExtensionToPatterns(fileIncludes, getFileTypeExtension());
174 ThemeBuilderUtils.addExtensionToPatterns(fileExcludes, getFileTypeExtension());
175 ThemeBuilderUtils.addExtensionToPatterns(pluginFileExcludes, getFileTypeExtension());
176
177 List<File> pluginThemeFiles = new ArrayList<File>();
178 for (Map.Entry<String, File> pluginMapping : this.themePluginDirsMap.entrySet()) {
179 String pluginName = pluginMapping.getKey();
180 File pluginDirectory = pluginMapping.getValue();
181
182
183 String[] adjustedFileExcludes = null;
184 if (pluginFileExcludes != null) {
185 adjustedFileExcludes = new String[pluginFileExcludes.length];
186
187 for (int i = 0; i < pluginFileExcludes.length; i++) {
188 adjustedFileExcludes[i] = StringUtils.removeStart(pluginFileExcludes[i], pluginName + "/");
189 }
190 }
191
192 pluginThemeFiles.addAll(ThemeBuilderUtils.getDirectoryFiles(pluginDirectory, fileIncludes,
193 adjustedFileExcludes));
194 }
195
196 themeFiles.put(PLUGIN_FILES_KEY, pluginThemeFiles);
197
198
199 List<File> subDirThemeFiles = new ArrayList<File>();
200
201 subDirThemeFiles.addAll(ThemeBuilderUtils.getDirectoryFiles(getFileTypeSubDirectory(), fileIncludes,
202 fileExcludes));
203
204
205 addAdditionalFiles(subDirThemeFiles);
206
207 themeFiles.put(SUBDIR_FILES_KEY, subDirThemeFiles);
208
209 if (LOG.isDebugEnabled()) {
210 LOG.debug("Found " + subDirThemeFiles.size() + "file(s) for theme " + this.themeName);
211 }
212
213 return themeFiles;
214 }
215
216
217
218
219
220
221
222
223 protected String[] getFileIncludes() {
224 return new String[] {"**/*" + getFileTypeExtension()};
225 }
226
227
228
229
230
231
232
233
234
235
236
237
238
239 protected String[] getFileExcludes() {
240 String[] excludes = null;
241
242 if (this.themeProperties.containsKey(getExcludesConfigKey())) {
243 String excludesString = this.themeProperties.getProperty(getExcludesConfigKey());
244
245 excludes = excludesString.split(",");
246 }
247
248 return excludes;
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262
263 protected File getFileTypeSubDirectory() {
264 File subDirectory = new File(this.themeDirectory, getFileTypeDirectoryName());
265
266 if (!subDirectory.exists()) {
267 throw new RuntimeException(
268 "Directory for file type " + getFileTypeDirectoryName() + " does not exist for theme: "
269 + this.themeName);
270 }
271
272 return subDirectory;
273 }
274
275
276
277
278
279
280
281
282
283
284
285
286 protected File createMergedFile(boolean minified) {
287 String mergedFileName = this.themeName + "." + this.projectVersion;
288
289 if (minified) {
290 mergedFileName += ThemeBuilderConstants.MIN_FILE_SUFFIX;
291 }
292
293 mergedFileName += getFileTypeExtension();
294
295 return new File(getFileTypeSubDirectory(), mergedFileName);
296 }
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311 protected void mergeFiles(List<File> filesToMerge, File mergedFile) throws IOException {
312 OutputStream out = null;
313 OutputStreamWriter outWriter = null;
314 InputStreamReader reader = null;
315
316 LOG.info("Creating merged file: " + mergedFile.getPath());
317
318 try {
319 out = new FileOutputStream(mergedFile);
320 outWriter = new OutputStreamWriter(out);
321
322 for (File fileToMerge : filesToMerge) {
323 reader = new FileReader(fileToMerge);
324
325 String fileContents = IOUtils.toString(reader);
326 if ((fileContents == null) || "".equals(fileContents)) {
327 continue;
328 }
329
330 fileContents = processMergeFileContents(fileContents, fileToMerge, mergedFile);
331
332 outWriter.append(fileContents);
333 outWriter.flush();
334 }
335 } finally {
336 if (out != null) {
337 out.close();
338 }
339
340 if (reader != null) {
341 reader.close();
342 }
343 }
344 }
345
346
347
348
349
350
351 protected abstract String getFileTypeExtension();
352
353
354
355
356
357
358 protected abstract String getFileTypeDirectoryName();
359
360
361
362
363
364
365
366 protected abstract String getExcludesConfigKey();
367
368
369
370
371
372
373
374 protected abstract String getFileListingConfigKey();
375
376
377
378
379
380
381 protected abstract void addAdditionalFiles(List<File> themeFiles);
382
383
384
385
386
387
388
389
390
391 protected abstract List<File> sortThemeFiles(List<File> pluginFiles, List<File> subDirFiles);
392
393
394
395
396
397
398
399
400
401
402
403 protected abstract String processMergeFileContents(String fileContents, File fileToMerge, File mergedFile)
404 throws IOException;
405
406
407
408
409
410
411
412
413 protected abstract void minify(File mergedFile, File minifiedFile) throws IOException;
414
415
416
417
418
419
420
421
422 protected List<String> getThemePropertyValue(String propertyKey) {
423 return ThemeBuilderUtils.getPropertyValueAsList(propertyKey, this.themeProperties);
424 }
425
426
427
428
429
430
431
432
433 protected List<File> getPropertyValueAsPluginDirs(String propertyKey) {
434 List<File> pluginDirs = null;
435
436 List<String> pluginNames = ThemeBuilderUtils.getPropertyValueAsList(propertyKey, this.themeProperties);
437
438 if (pluginNames != null && !pluginNames.isEmpty()) {
439 pluginDirs = new ArrayList<File>();
440
441 for (String pluginName : pluginNames) {
442 pluginName = pluginName.toLowerCase();
443
444 if (!this.themePluginDirsMap.containsKey(pluginName)) {
445 throw new RuntimeException(
446 "Invalid plugin name: " + pluginName + " in configuration for property " + propertyKey);
447 }
448
449 pluginDirs.add(this.themePluginDirsMap.get(pluginName));
450 }
451 }
452
453 return pluginDirs;
454 }
455
456
457
458
459
460
461
462
463 protected List<File> addMissingPluginDirs(List<File> pluginList) {
464 List<File> allPluginDirs = new ArrayList<File>();
465
466 if (pluginList != null) {
467 allPluginDirs.addAll(pluginList);
468 }
469
470 Collection<File> allPlugins = this.themePluginDirsMap.values();
471 for (File pluginDir : allPlugins) {
472 if (!allPluginDirs.contains(pluginDir)) {
473 allPluginDirs.add(pluginDir);
474 }
475 }
476
477 return allPluginDirs;
478 }
479 }