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 com.google.javascript.jscomp.CompilationLevel;
19  import com.google.javascript.jscomp.Compiler;
20  import com.google.javascript.jscomp.CompilerOptions;
21  import com.google.javascript.jscomp.SourceFile;
22  import org.apache.commons.lang.StringUtils;
23  import org.apache.log4j.Logger;
24  import org.kuali.rice.krad.theme.util.ThemeBuilderConstants;
25  import org.kuali.rice.krad.theme.util.ThemeBuilderUtils;
26  
27  import java.io.File;
28  import java.io.FileInputStream;
29  import java.io.FileOutputStream;
30  import java.io.IOException;
31  import java.io.InputStream;
32  import java.io.InputStreamReader;
33  import java.io.OutputStream;
34  import java.io.OutputStreamWriter;
35  import java.util.ArrayList;
36  import java.util.Arrays;
37  import java.util.Collections;
38  import java.util.List;
39  import java.util.Map;
40  import java.util.Properties;
41  import java.util.Set;
42  import java.util.HashSet;
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  public class ThemeJsFilesProcessor extends ThemeFilesProcessor {
58      private static final Logger LOG = Logger.getLogger(ThemeJsFilesProcessor.class);
59  
60      public ThemeJsFilesProcessor(String themeName, File themeDirectory, Properties themeProperties,
61              Map<String, File> themePluginDirsMap, File workingDir, String projectVersion) {
62          super(themeName, themeDirectory, themeProperties, themePluginDirsMap, workingDir, projectVersion);
63      }
64  
65      
66  
67  
68      @Override
69      protected String getFileTypeExtension() {
70          return ThemeBuilderConstants.FileExtensions.JS;
71      }
72  
73      
74  
75  
76      @Override
77      protected String getExcludesConfigKey() {
78          return ThemeBuilderConstants.ThemeConfiguration.JS_EXCLUDES;
79      }
80  
81      
82  
83  
84      @Override
85      protected String getFileTypeDirectoryName() {
86          return ThemeBuilderConstants.ThemeDirectories.SCRIPTS;
87      }
88  
89      
90  
91  
92      @Override
93      protected String getFileListingConfigKey() {
94          return ThemeBuilderConstants.DerivedConfiguration.THEME_JS_FILES;
95      }
96  
97      
98  
99  
100 
101 
102     @Override
103     protected void addAdditionalFiles(List<File> themeFiles) {
104         File kradScriptDir = new File(this.workingDir, ThemeBuilderConstants.KRAD_SCRIPTS_DIRECTORY);
105 
106         themeFiles.addAll(ThemeBuilderUtils.getDirectoryFiles(kradScriptDir, getFileIncludes(), null));
107     }
108 
109     
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130     @Override
131     protected List<File> sortThemeFiles(List<File> pluginFiles, List<File> subDirFiles) {
132         List<String> loadJsFirst = getThemePropertyValue(ThemeBuilderConstants.ThemeConfiguration.JS_LOAD_FIRST);
133         List<String> loadJsLast = getThemePropertyValue(ThemeBuilderConstants.ThemeConfiguration.JS_LOAD_LAST);
134 
135         List<String> pluginJsLoadOrder = getThemePropertyValue(
136                 ThemeBuilderConstants.ThemeConfiguration.PLUGIN_JS_LOAD_ORDER);
137         List<String> jsLoadOrder = getThemePropertyValue(ThemeBuilderConstants.ThemeConfiguration.THEME_JS_LOAD_ORDER);
138 
139         
140         List<String> kradScriptOrder = null;
141         try {
142             kradScriptOrder = retrieveKradScriptLoadOrder();
143         } catch (IOException e) {
144             throw new RuntimeException("Unable to pull KRAD load order property key", e);
145         }
146 
147         if (kradScriptOrder != null) {
148             if (jsLoadOrder == null) {
149                 jsLoadOrder = new ArrayList<String>();
150             }
151 
152             jsLoadOrder.addAll(0, kradScriptOrder);
153         }
154 
155         return ThemeBuilderUtils.orderFiles(pluginFiles, subDirFiles, loadJsFirst, loadJsLast, pluginJsLoadOrder,
156                 jsLoadOrder);
157     }
158 
159     
160 
161 
162 
163 
164 
165 
166 
167 
168 
169 
170 
171 
172 
173 
174     protected List<String> retrieveKradScriptLoadOrder() throws IOException {
175         List<String> scriptLoadOrder = new ArrayList<String>();
176 
177         File kradScriptsDir = new File(this.workingDir, ThemeBuilderConstants.KRAD_SCRIPTS_DIRECTORY);
178 
179         File loadPropertiesFile = new File(kradScriptsDir, ThemeBuilderConstants.KRAD_SCRIPT_LOAD_PROPERTIES_FILE);
180         if (!loadPropertiesFile.exists()) {
181             throw new RuntimeException("load.properties file not found in KRAD scripts directory");
182         }
183 
184         Properties loadProperties = null;
185 
186         FileInputStream fileInputStream = null;
187         try {
188             fileInputStream = new FileInputStream(loadPropertiesFile);
189 
190             loadProperties = new Properties();
191             loadProperties.load(fileInputStream);
192         } finally {
193             if (fileInputStream != null) {
194                 fileInputStream.close();
195             }
196         }
197 
198         
199         if (loadProperties.containsKey(ThemeBuilderConstants.LOAD_ORDER_PROPERTY_KEY)) {
200             scriptLoadOrder = ThemeBuilderUtils.getPropertyValueAsList(ThemeBuilderConstants.LOAD_ORDER_PROPERTY_KEY,
201                     loadProperties);
202         }
203 
204         
205         List<String> scriptFileNames = ThemeBuilderUtils.getDirectoryFileNames(kradScriptsDir, null, null);
206         if (scriptFileNames != null) {
207             for (String scriptFileName : scriptFileNames) {
208                 
209                 String baseScriptFileName = StringUtils.substringBeforeLast(scriptFileName, ".");
210 
211                 if (!scriptLoadOrder.contains(baseScriptFileName)) {
212                     scriptLoadOrder.add(baseScriptFileName);
213                 }
214             }
215         }
216 
217         return scriptLoadOrder;
218     }
219 
220     
221 
222 
223 
224 
225 
226     @Override
227     protected String processMergeFileContents(String fileContents, File fileToMerge, File mergedFile)
228             throws IOException {
229         if ((fileContents != null) && !fileContents.matches(
230                 ThemeBuilderConstants.Patterns.JS_SEMICOLON_PATTERN)) {
231             fileContents += ";";
232         }
233 
234         return fileContents;
235     }
236 
237     
238 
239 
240 
241 
242 
243 
244 
245 
246 
247 
248     @Override
249     protected void minify(File mergedFile, File minifiedFile) throws IOException {
250         InputStream in = null;
251         OutputStream out = null;
252         OutputStreamWriter writer = null;
253         InputStreamReader reader = null;
254 
255         LOG.info("Populating minified JS file: " + minifiedFile.getPath());
256 
257         try {
258             out = new FileOutputStream(minifiedFile);
259             writer = new OutputStreamWriter(out);
260 
261             in = new FileInputStream(mergedFile);
262             reader = new InputStreamReader(in);
263 
264             CompilerOptions options = new CompilerOptions();
265             CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
266             options.setLanguageIn(CompilerOptions.LanguageMode.ECMASCRIPT5);
267             options.setExtraAnnotationNames(ignoredAnnotations());
268 
269             SourceFile input = SourceFile.fromInputStream(mergedFile.getName(), in);
270             List<SourceFile> externs = Collections.emptyList();
271 
272             Compiler compiler = new Compiler();
273             compiler.compile(externs, Arrays.asList(input), options);
274 
275             writer.append(compiler.toSource());
276             writer.flush();
277         } finally {
278             if (in != null) {
279                 in.close();
280             }
281 
282             if (out != null) {
283                 out.close();
284             }
285         }
286     }
287 
288     
289 
290 
291 
292 
293     protected Set<String> ignoredAnnotations() {
294         Set<String> annotations = new HashSet<String>();
295         annotations.add("dtopt");
296         annotations.add("result");
297         annotations.add("cat");
298         annotations.add("parm");
299 
300         return annotations;
301     }
302 
303 }