1 18 package net.sf.uitags.build; 19 20 import java.io.BufferedReader ; 21 import java.io.File ; 22 import java.io.FileFilter ; 23 import java.io.FileInputStream ; 24 import java.io.FileNotFoundException ; 25 import java.io.FileOutputStream ; 26 import java.io.IOException ; 27 import java.io.InputStreamReader ; 28 import java.io.PrintStream ; 29 import java.util.ArrayList ; 30 import java.util.HashSet ; 31 import java.util.List ; 32 import java.util.Set ; 33 34 import org.apache.maven.plugin.AbstractMojo; 35 import org.apache.maven.plugin.MojoFailureException; 36 37 44 public final class SimpleJsFileSizeReducer extends AbstractMojo { 45 49 54 private String inputDir; 55 60 private String outputDir; 61 62 63 64 68 private File jsInputDirectory; 69 private File jsOutputDirectory; 70 private JsFileFilter fileFilter; 71 private JsDirectoryFilter directoryFilter; 72 73 74 75 79 82 private void init() throws MojoFailureException { 83 this.jsInputDirectory = getDirectoryHandle(this.inputDir, false); 84 this.jsOutputDirectory = getDirectoryHandle(this.outputDir, true); 85 86 this.fileFilter = new JsFileFilter(); 87 this.directoryFilter = new JsDirectoryFilter(); 88 } 89 90 private File getDirectoryHandle(String dirPath, boolean createIfNotExists) 91 throws MojoFailureException { 92 File dir = new File (dirPath); 93 if (!dir.exists() && createIfNotExists) { 94 dir.mkdirs(); 95 } 96 97 if (!dir.isDirectory()) { 98 getLog().error("Invalid directory name: " + dirPath); 99 throw new MojoFailureException("Invalid directory name: " + dirPath); 100 } 101 return dir; 102 } 103 104 105 106 110 private File [] getJsFilePaths(File baseDir) { 111 File [] jsFiles = baseDir.listFiles(this.fileFilter); 112 List allJsFiles = new ArrayList (); 113 addFilesToList(jsFiles, allJsFiles); 114 115 File [] subDirs = baseDir.listFiles(this.directoryFilter); 116 for (int i = 0; i < subDirs.length; ++i) { 117 jsFiles = getJsFilePaths(subDirs[i]); 118 addFilesToList(jsFiles, allJsFiles); 119 } 120 return (File []) allJsFiles.toArray(new File [allJsFiles.size()]); 121 } 122 123 private void addFilesToList(File [] files, List list) { 124 for (int i = 0; i < files.length; ++i) { 125 list.add(files[i]); 126 } 127 } 128 129 private File [] getAllSourceJsFilePaths() { 130 return getJsFilePaths(this.jsInputDirectory); 131 } 132 133 private File [] getAllTargetJsFilePaths() { 134 return getJsFilePaths(this.jsOutputDirectory); 135 } 136 137 private String stripFileContent(File jsFile) throws IOException { 138 BufferedReader reader = new BufferedReader ( 139 new InputStreamReader (new FileInputStream (jsFile))); 140 141 String line; 142 CommentStripper stripper = new CommentStripper(); 143 StringBuffer buffer = new StringBuffer (); 144 while ((line = reader.readLine()) != null) { 145 line = stripComments(line, stripper) + "\n"; 146 line = stripEverythingIfOnlyContainSpaces(line); 147 buffer.append(line); 148 } 149 return buffer.toString(); 150 } 151 152 private void performFileSizeReduction(File jsFile) { 153 try { 154 String content = stripFileContent(jsFile); 155 getOutputStreamFromInputFile(jsFile).print(content); 156 } 157 catch (IOException e) { 158 throw new RuntimeException (e); 159 } 160 } 161 162 private PrintStream getOutputStreamFromInputFile(File inputFile) 163 throws FileNotFoundException { 164 String relativePath = getPathRelativeToInputDirectory(inputFile); 165 String outputPath = this.jsOutputDirectory.getAbsolutePath() + 166 "/" + relativePath; 167 ensureDirectoryExists(new File (outputPath).getParentFile()); 168 return new PrintStream (new FileOutputStream (outputPath)); 169 } 170 171 private void ensureDirectoryExists(File directory) { 172 if (!directory.exists()) { 173 directory.mkdir(); 174 } 175 else if (!directory.isDirectory()) { 176 throw new IllegalArgumentException ( 177 directory.getName() + " is not a directory."); 178 } 179 } 180 181 private String stripComments(String line, CommentStripper stripper) { 182 stripper.startLine(); 183 for (int i = 0; i < line.length(); ++i) { 184 if (!stripper.processCharacter(line.charAt(i))) { 185 return stripper.endLine(); 186 } 187 } 188 return stripper.endLine(); 189 } 190 191 private String stripEverythingIfOnlyContainSpaces(String line) { 192 return line.replaceFirst("^[ \t\n]*$", ""); 193 } 194 195 private String getPathRelativeToInputDirectory(File file) { 196 String baseName = StringUtils.escapePattern( 197 this.jsInputDirectory.getPath()); 198 String path = file.getPath().replaceFirst(baseName, ""); 199 return path.replaceFirst("^/*", ""); 200 } 201 202 public void execute() throws MojoFailureException { 203 init(); 204 205 File [] targetJsFiles = getAllTargetJsFilePaths(); 206 getLog().info("Deleting files in target directory:"); 207 for (int i = 0; i < targetJsFiles.length; ++i) { 208 getLog().info("Deleting " + targetJsFiles[i].getAbsolutePath()); 209 targetJsFiles[i].delete(); 210 } 211 212 File [] sourceJsFiles = getAllSourceJsFilePaths(); 213 System.out.println("Reducing the size of source javascript files:"); 214 for (int i = 0; i < sourceJsFiles.length; ++i) { 215 getLog().info("Stripping " + sourceJsFiles[i].getAbsolutePath()); 216 performFileSizeReduction(sourceJsFiles[i]); 217 } 218 } 219 220 221 222 226 public static void main(String args[]) throws MojoFailureException { 227 if (args.length != 2) { 228 printUsage(); 229 } 230 231 SimpleJsFileSizeReducer reducer = new SimpleJsFileSizeReducer(); 232 reducer.inputDir = args[0]; 233 reducer.outputDir = args[1]; 234 reducer.execute(); 235 } 236 237 private static void printUsage() { 238 System.err.println("Usage: PROGRAM INPUT_BASE_DIR OUTPUT_BASE_DIR"); 239 System.exit(1); 240 } 241 242 243 244 248 private static class JsFileFilter implements FileFilter { 249 public boolean accept(File file) { 250 if (file.isFile() && file.getPath().endsWith(".js")) { 251 return true; 252 } 253 return false; 254 } 255 } 256 257 private static class JsDirectoryFilter implements FileFilter { 258 private static Set blackList = new HashSet (); 259 260 static { 261 blackList.add("CVS"); 262 blackList.add("excludes"); 263 } 264 265 public boolean accept(File file) { 266 if (file.isDirectory() && 267 !blackList.contains(file.getName())) { 268 return true; 269 } 270 return false; 271 } 272 } 273 274 private static class CommentStripper { 275 private StringBuffer buffer; 276 private boolean insideSingleQuote; 277 private boolean insideDoubleQuote; 278 private boolean slashEncountered; 279 private boolean asteriskEncountered; 280 private boolean insideMultiLinesComment; 281 282 private CommentStripper() { 283 this.insideMultiLinesComment = false; 284 this.asteriskEncountered = false; 285 } 286 287 private void startLine() { 288 this.buffer = new StringBuffer (); 289 this.insideSingleQuote = false; 290 this.insideDoubleQuote = false; 291 this.slashEncountered = false; 292 } 294 295 300 private boolean processCharacter(char currentChar) { 301 if (shouldIgnoreMultiLinesCommentContent(currentChar)) { 302 return true; 303 } 304 305 switch (currentChar) { 306 case '\'' : 307 toggleSingleQuote(); 308 break; 309 case '"' : 310 toggleDoubleQuote(); 311 break; 312 case '/' : 313 if (checkIfSingleLineCommentStarted()) { 314 return false; 315 } 316 if (this.insideMultiLinesComment && 317 checkIfMultiLinesCommentEnded()) { 318 return true; 319 } 320 break; 321 case '*' : 322 if (this.insideMultiLinesComment) { 323 this.asteriskEncountered = true; 324 } 325 else { 326 this.insideMultiLinesComment = checkIfMultiLinesCommentStarted(); 327 } 328 break; 329 default : 330 makeUpForAnyIgnoredSlash(); 331 dismissAnyPosibility(); 332 } 333 storeOnlyIfConfirmed(currentChar); 334 335 return true; 336 } 337 338 private boolean shouldIgnoreMultiLinesCommentContent(char currentChar) { 339 return this.insideMultiLinesComment && 340 !hasPosibilityToEndMultiLinesComment(currentChar); 341 } 342 343 private boolean hasPosibilityToEndMultiLinesComment(char currentChar) { 344 return this.asteriskEncountered || currentChar == '*'; 345 } 346 347 private void toggleSingleQuote() { 348 this.insideSingleQuote = !this.insideSingleQuote; 349 } 350 351 private void toggleDoubleQuote() { 352 this.insideDoubleQuote = !this.insideDoubleQuote; 353 } 354 355 private boolean insideQuote() { 356 return this.insideSingleQuote || this.insideDoubleQuote; 357 } 358 359 private boolean checkIfSingleLineCommentStarted() { 360 if (!insideQuote()) { 361 if (this.slashEncountered) { 362 this.slashEncountered = false; 363 return true; 364 } 365 this.slashEncountered = true; 366 } 367 return false; 368 } 369 370 private boolean checkIfMultiLinesCommentStarted() { 371 if (!insideQuote()) { 372 if (this.slashEncountered) { 373 this.slashEncountered = false; 374 return true; 375 } 376 } 377 return false; 378 } 379 380 private boolean checkIfMultiLinesCommentEnded() { 381 if (this.asteriskEncountered) { 382 this.insideMultiLinesComment = false; 383 this.asteriskEncountered = false; 384 this.slashEncountered = false; 385 return true; 386 } 387 return false; 388 } 389 390 private void dismissAnyPosibility() { 391 this.slashEncountered = false; 392 this.asteriskEncountered = false; 393 } 394 395 private void makeUpForAnyIgnoredSlash() { 396 if (this.slashEncountered) { 397 storeIfNotInsideComment('/'); 398 } 399 } 400 401 private void storeOnlyIfConfirmed(char currentChar) { 402 if (!this.slashEncountered) { 403 storeIfNotInsideComment(currentChar); 404 } 405 } 406 407 private void storeIfNotInsideComment(char currentChar) { 408 if (!this.insideMultiLinesComment) { 409 this.buffer.append(currentChar); 410 } 411 } 412 413 private String endLine() { 414 makeUpForAnyIgnoredSlash(); 415 return this.buffer.toString(); 416 } 417 } 418 } 419 | Popular Tags |