View Javadoc

1   package org.appfuse.tool;
2   
3   import java.io.File;
4   import java.io.FileNotFoundException;
5   import java.io.IOException;
6   import java.util.Iterator;
7   import java.util.Vector;
8   import java.util.regex.Matcher;
9   import java.util.regex.Pattern;
10  
11  import org.apache.commons.io.FileUtils;
12  import org.apache.maven.plugin.logging.Log;
13  import org.apache.maven.plugin.logging.SystemStreamLog;
14  import org.apache.tools.ant.BuildException;
15  import org.apache.tools.ant.DirectoryScanner;
16  import org.apache.tools.ant.types.FileSet;
17  
18  
19  /**
20   * This class is almost a complete copy of replacepackages
21   * by Ben Gill.  These utility methods can be used in the
22   * plugin to change package names of appfuse source
23   * contributions.  Liberties have been taken to make this
24   * open source code just work here. Some methods were removed
25   * and logging now uses SystemStreamLog from Apache (Maven)
26   *
27   * @author <a href="mailto:david@capehenrytech.com">David L. Whitehurst</a>
28   */
29  public class RenamePackages {
30  
31      static final boolean SAVE_FILE = true;
32      static final boolean DONT_SAVE_FILE = false;
33      boolean debug = false;
34      private String baseDir = "src"; // root
35      private String workBaseDir = "null"; // actually called null
36      private String existingPkgName = "org.appfuse"; // AppFuse
37      private String newPkgName;
38      private String existingPkgPath;
39      private String newPkgPath;
40      protected transient final Log log = new SystemStreamLog();
41  
42      StringBuffer logOutput = new StringBuffer();
43  
44      String[] invalidFileTypes = new String[]{"class", "jar", "jpg", "gif", "png", "ico"};
45  
46      private Vector filesets = new Vector();
47  
48      /**
49       * Constructor
50       */
51      public RenamePackages(String newPackage) {
52          this.newPkgName = newPackage;
53      }
54  
55      /**
56       * simple method to add filesets
57       *
58       * @param fileset
59       */
60      public void addFileset(FileSet fileset) {
61          filesets.add(fileset);
62      }
63  
64      /**
65       * Override the default set of invalid file types that will be moved to the
66       * new package structure.
67       * <p/>
68       * The invalidFileTypes must be a comma
69       * separated list of file extensions
70       * for example "class,jar,exe"
71       *
72       * @param invalidFileTypes
73       */
74      public void setInvalidFileTypes(String invalidFileTypes) {
75          this.invalidFileTypes = invalidFileTypes.split(",");
76  
77          if (debug) {
78              log.debug("default invalidFileTypes overriden with [" + invalidFileTypes
79                      + "]");
80          }
81      }
82  
83      /**
84       * Set the base directory. The base directory will be where the Task starts
85       * to recursively look for files with the given package name in it. This
86       * method will be called by ANT when it invokes the Task.
87       *
88       * @param baseDir
89       */
90      public void setBaseDir(String baseDir) {
91          if (!new File(baseDir.trim()).exists()) {
92              throw new ExceptionInInitializerError("Base dir [" + baseDir.trim()
93                      + "] does not exist");
94          }
95          this.baseDir = correctFileSeparators(baseDir.trim());
96          if (this.baseDir != null) {
97              if (this.baseDir.endsWith(File.separator)) {
98                  this.workBaseDir = this.baseDir.substring(0, this.baseDir
99                          .length())
100                         + ".work";
101             } else {
102                 this.workBaseDir = this.baseDir + ".work";
103             }
104 
105             if (debug) {
106                 log.debug("Set workBaseDir to [" + this.workBaseDir + "]");
107             }
108         }
109     }
110 
111     /**
112      * Validates the packagename
113      *
114      * @param packageName
115      * @throws ExceptionInInitializerError if the package name is invalid
116      */
117     private void validatePackageName(String packageName)
118             throws ExceptionInInitializerError {
119         if (packageName.indexOf("/") != -1) {
120             throw new ExceptionInInitializerError("packageName [" + packageName
121                     + "] is invalid because it contains slashes");
122         }
123         if (packageName.indexOf("\\") != -1) {
124             throw new ExceptionInInitializerError("packageName [" + packageName
125                     + "] is invalid because it contains slashes");
126         }
127     }
128 
129     /**
130      * Strips out start and end dots
131      *
132      * @param packageName
133      * @return package name without starting and ending dots
134      */
135     private String stripUnwantedDots(String packageName) {
136 
137         while (packageName.endsWith(".")) {
138             packageName = packageName.substring(0, packageName.length() - 1);
139         }
140         while (packageName.startsWith(".")) {
141             packageName = packageName.substring(1);
142         }
143 
144         if (debug) {
145             log.debug("returning stripped package name of [" + packageName + "]");
146         }
147 
148         return packageName;
149     }
150 
151     /**
152      * Set the existing package name. This will become the string that the Task
153      * looks to replace in the files look for files with the given package name
154      * in it. This method will be called by ANT when it invokes the Task.
155      *
156      * @param existingPkgName
157      */
158     public void setExistingPkgName(String existingPkgName) throws Exception {
159 
160         log.info("existingPkgName came in as [" + existingPkgName + "]");
161 
162         this.existingPkgName = stripUnwantedDots(existingPkgName.trim());
163         validatePackageName(this.existingPkgName);
164         if (this.existingPkgName.length() == 0) {
165             throw new Exception("Unsupported operation - cannot "
166                     + " repackage from empty package name as would "
167                     + " not know which imports to expand out");
168         }
169     }
170 
171     /**
172      * Set the new package name. This will become the package name and replace
173      * the existing package name in the source files. This method will be called
174      * by ANT when it invokes the Task.
175      *
176      * @param newPkgName
177      * @throws Exception
178      */
179     public void setNewPkgName(String newPkgName) throws Exception {
180         log.info("newPkgName came in as [" + newPkgName + "]");
181 
182         this.newPkgName = stripUnwantedDots(newPkgName.trim());
183         validatePackageName(this.newPkgName);
184         if (this.newPkgName.length() == 0) {
185             throw new Exception("Unimplemented operation");
186         }
187     }
188 
189     /**
190      * Set the package paths. Replace the . delimiter with the relevant file
191      * separator based on the o/s we are running on.
192      */
193     private void setPackagePaths() {
194         this.existingPkgPath = getPackagePath(existingPkgName);
195         this.newPkgPath = getPackagePath(newPkgName);
196 
197         if (debug) {
198             log.debug("Set existing package path as [" + existingPkgPath + "]");
199             log.debug("Set new package path as [" + newPkgPath + "]");
200         }
201     }
202 
203     /**
204      * Set the new package name. This will become the package name and replace
205      * the existing package name in the source files. This method will be called
206      * by ANT when it invokes the Task.
207      *
208      * @param pkgName
209      * @return path of the pkg name
210      */
211     private String getPackagePath(String pkgName) {
212         String[] pkgNames = pkgName.split("\\.");
213         String aPath = "";
214 
215         for (int i = 0; i < pkgNames.length; i++) {
216             if (aPath.length() != 0) {
217                 aPath += File.separator;
218             }
219 
220             aPath += pkgNames[i];
221         }
222         return aPath;
223     }
224 
225     /**
226      * Creates a new directory, if it does not exist already
227      *
228      * @param directoryName
229      */
230     private void createDirectory(String directoryName) {
231         File dir = new File(directoryName);
232 
233         if (!dir.exists()) {
234             if (dir.mkdirs()) {
235                 String message = "Created directory [" + directoryName + "]";
236 
237                 if (debug) {
238                     log.debug(message);
239                 }
240             } else {
241                 log.error("Failed to create directory [" + directoryName + "]");
242             }
243         }
244     }
245 
246     /*
247      * This method gets called recursively (mainly by itself) and walks through
248      * the directory structure looking for files with existingPkgPath in their
249      * fully qualified (absolute) names.
250      *
251      * If a file is found, then it is parsed for the existingPkgName and any
252      * instance of this string will be replaced by the newPkgName. The file is
253      * then saved back out in its new package directory.
254      *
255      * @param inDirName the directory to search
256      */
257     private void repackage(String inDirName, String inWorkDirName)
258             throws IOException {
259 
260         if (debug) {
261             log.debug("Inside repackage inDirName is [" + inDirName + "]");
262             log.debug("Inside repackage inWorkDirName is [" + inWorkDirName + "]");
263         }
264 
265         String[] files = new File(inDirName).list();
266 
267         if (files == null) {
268             return;
269         }
270 
271         if (debug) {
272             log.debug("There are [" + files.length + "] files in dir [" + inDirName
273                     + "]");
274         }
275 
276         for (int i = 0; i < files.length; i++) {
277             if (debug) {
278                 log.debug("file is [" + files[i] + "]");
279             }
280 
281             String fileName = inDirName + File.separator + files[i];
282             File aFile = new File(fileName);
283 
284             if (files[i].equals("CVS")) {
285                 if (debug) {
286                     log.debug("ignoring CVS dir");
287                 }
288             } else if (aFile.isDirectory()) {
289                 if (debug) {
290                     log.debug("Got a dir [" + fileName + "]");
291                 }
292 
293                 String newDirName = inDirName + File.separator + files[i];
294                 String newWorkDirName = inWorkDirName + File.separator
295                         + files[i];
296 
297                 if (isOldPackageDir(fileName)) {
298                     String newPath = convertOldPackageDirName(fileName);
299 
300                     if (debug) {
301                         log.debug("found old package dir [" + fileName + "] "
302                                 + "newPath is [" + newPath.toString() + "]");
303                     }
304                     createDirectory(newPath.toString());
305 
306                 } else {
307 
308                     // Replace existing baseDir
309                     String newPath = this.workBaseDir
310                             + fileName.substring(this.baseDir.length());
311 
312                     if (debug) {
313                         log.debug("found dir outside old package [" + fileName + "] "
314                                 + "newPath is [" + newPath + "]");
315                     }
316                     createDirectory(newPath);
317                 }
318 
319                 if (debug) {
320                     log.debug("Recursing with [" + newDirName + "]");
321                 }
322 
323                 repackage(newDirName, newWorkDirName);
324 
325             } else {
326                 // Normal file
327                 if (debug) {
328                     log.debug("Processing file [" + fileName + "] existingPkgPath is ["
329                             + existingPkgPath + "]");
330                 }
331 
332                 // Should we process this file at all or leave it?
333                 int existingPathIndexPos = fileName.indexOf(existingPkgPath);
334 
335                 if (existingPathIndexPos != -1) {
336                     // Normal file in old package structure
337                     if (debug) {
338                         log.debug("found file with existing package name ["
339                                 + fileName + "]");
340                     }
341 
342                     String newPath = convertOldPackageDirName(fileName
343                             .substring(0, fileName.lastIndexOf(File.separator)));
344                     String newFileName = newPath
345                             + fileName.substring(fileName
346                             .lastIndexOf(File.separator));
347 
348                     if (debug) {
349                         log.debug("creating directory [" + newPath + "]");
350                     }
351 
352                     createDirectory(newPath);
353 
354                     if (isValidFileType(fileName)) {
355                         String output = changePackageNamesInFile(fileName,
356                                 RenamePackages.DONT_SAVE_FILE);
357 
358                         if (debug) {
359                             log.debug("Saving file [" + fileName
360                                     + "] to new package directory ["
361                                     + newFileName + "]");
362                         }
363 
364                         toFile(newFileName, output);
365                     } else {
366                         if (debug) {
367                             log.debug("Renaming file non valid file type ["
368                                     + fileName + "]");
369                         }
370 
371                         if (!aFile.renameTo(new File(newFileName))) {
372                             log.error("Failed to rename file [" + fileName + "] to ["
373                                     + newFileName + "]");
374                         }
375                     }
376                 } else {
377                     // Normal file - not in old package structure
378 
379                     // Stip off existing baseDir
380                     String newFileName = this.workBaseDir
381                             + fileName.substring(this.baseDir.length());
382 
383                     if (aFile.renameTo(new File(newFileName))) {
384                         if (debug) {
385                             log.debug("Saved file [" + newFileName
386                                     + "] to new directory structure");
387                         }
388                     } else {
389                         log.error("Failed to rename file [" + fileName + "] to ["
390                                 + newFileName + "] to new directory structure");
391                     }
392                 }
393             }
394         }
395     }
396 
397     /*
398      * This method gets called recursively (mainly by itself) and walks through
399      * the directory structure looking for ANY valid files with existingPkgPath.
400      *
401      * If a file is found, then it is parsed then it is output for the caller to
402      * check.
403      *
404      * @param inDirName the directory to search
405      */
406     private void checkSummary(String inDirName)
407             throws IOException {
408         if (debug) {
409             log.debug("Inside checkSummary inDirName is [" + inDirName + "]");
410         }
411 
412         String[] files = new File(inDirName).list();
413 
414         if (files == null) {
415             return;
416         }
417 
418         if (debug) {
419             log.debug("There are [" + files.length + "] files in dir [" + inDirName + "]");
420         }
421 
422         for (String file : files) {
423 
424             if (debug) {
425                 log.debug("file is [" + file + "]");
426             }
427 
428             String fileName = inDirName + File.separator + file;
429             File aFile = new File(fileName);
430 
431             if (aFile.isDirectory()) {
432 
433                 if (debug) {
434                     log.debug("Got a dir [" + fileName + "]");
435                 }
436 
437                 String newDirName = inDirName + File.separator + file;
438 
439                 if (debug) {
440                     log.debug("Recursing with [" + newDirName + "]");
441                 }
442 
443                 checkSummary(newDirName);
444             } else {
445                 // Normal file
446                 if (debug) {
447                     log.debug("Checking file [" + fileName + "] existingPkgPath is ["
448                             + existingPkgPath + "]");
449                 }
450 
451                 if (isValidFileType(fileName)) {
452                     if (hasFileOldPathOrPkg(fileName)) {
453                         if (debug) {
454                             log.debug("File [" + fileName + "] still has old pkg [" + existingPkgPath + "]");
455                         }
456                     }
457                 }
458             }
459         }
460     }
461 
462 
463     private boolean matches(String patternStr, String fileContents) {
464 
465         Pattern pattern = Pattern.compile(patternStr);
466         Matcher matcher = pattern.matcher(fileContents);
467         return matcher.matches();
468     }
469 
470 
471     private boolean hasFileOldPathOrPkg(String fileName) {
472 
473         try {
474             String fileContents = fromFile(fileName);
475 
476             String patternStr = escape(existingPkgPath);
477 
478             if (matches(patternStr, fileContents)) {
479                 return true;
480             }
481 
482             patternStr = getUnixPath(existingPkgPath);
483             patternStr = escape(patternStr);
484 
485             if (matches(patternStr, fileContents)) {
486                 return true;
487             }
488 
489             patternStr = getWindowsPath(existingPkgPath);
490             patternStr = escape(patternStr);
491 
492             return matches(patternStr, fileContents);
493 
494         } catch (IOException e) {
495             log.error("Error loading fileContents in hasFileOldPathOrPkg [" + e.getMessage() + "]");
496             return false;
497         }
498 
499     }
500 
501     private String convertOldPackageDirName(String dirName) {
502         // Need to create new package directory
503         int startExistingPathIndexPos = dirName.indexOf(existingPkgPath);
504         int endExistingPathIndexPos = startExistingPathIndexPos
505                 + existingPkgPath.length();
506 
507         StringBuffer newPath = new StringBuffer();
508         newPath.append(this.workBaseDir);
509 
510         // Get the front bit
511         if (debug) {
512             log.debug("startExistingPathIndexPos is [" + startExistingPathIndexPos + "]");
513             log.debug("about to do substring on [" + dirName + "] positions ["
514                     + this.baseDir.length() + "] and [" + startExistingPathIndexPos
515                     + "]");
516         }
517 
518         String firstPartFileName = dirName.substring(this.baseDir.length(),
519                 startExistingPathIndexPos);
520 
521         if (debug) {
522             log.debug("firstPartFileName is [" + firstPartFileName + "]");
523         }
524 
525         newPath.append(firstPartFileName);
526         newPath.append(newPkgPath);
527 
528         String lastPartFileName = dirName.substring(endExistingPathIndexPos);
529 
530         if (debug) {
531             log.debug("appending lastPartFileName [" + lastPartFileName + "]");
532         }
533 
534         newPath.append(lastPartFileName);
535 
536         return newPath.toString();
537     }
538 
539 
540     private boolean isOldPackageDir(String dirName) {
541         if (debug) {
542             log.debug("inside isOldPackageDir with [" + dirName + "]");
543         }
544 
545         // Should we process this file at all or leave it?
546         int existingPathIndexPos = dirName.indexOf(existingPkgPath);
547 
548         if (existingPathIndexPos != -1) {
549             if (debug) {
550                 log.debug("found dir with existing package name [" + dirName + "]");
551             }
552             return true;
553         }
554 
555         if (debug) {
556             log.debug("dir [" + dirName + "] is not old package dir");
557         }
558 
559         return false;
560     }
561 
562     /*
563      * This method reads a file and returns a string suitable for some regex
564      * operation
565      *
566      * @param fileName the file name to open and read @return the file contents
567      */
568     public String fromFile(String fileName) throws IOException {
569         /*BufferedReader in = new BufferedReader(new FileReader(fileName));
570         StringBuffer fileContents = new StringBuffer();
571         String str;
572 
573         while ((str = in.readLine()) != null)
574         {
575             fileContents.append(str);
576             fileContents.append("\n");
577         }
578         in.close();
579         return fileContents.toString();*/
580         return FileUtils.readFileToString(new File(fileName), "UTF-8");
581     }
582 
583     /*
584      * This method saves a file to disk
585      *
586      * @param fileName the name of the file @param contents the files contents
587      * @throws IOException if there is an error writing the file
588      */
589     public void toFile(String fileName, String contents) throws IOException {
590         if (debug) {
591             log.debug("Saving file to fileName [" + fileName + "]");
592         }
593 
594         FileUtils.writeStringToFile(new File(fileName), contents, "UTF-8");
595         /*BufferedOutputStream bout = new BufferedOutputStream(
596                 new DataOutputStream(new FileOutputStream(fileName)));
597 
598         bout.write(contents.getBytes());
599         bout.flush();
600         bout.close();*/
601     }
602 
603     /**
604      * Checks to see if the file is a valid type
605      *
606      * @return true if the file is a valid type, else false
607      */
608     private boolean isValidFileType(String fileName) {
609         for (int i = 0; i < invalidFileTypes.length; i++) {
610             if (fileName.endsWith(invalidFileTypes[i])) {
611                 if (debug) {
612                     log.debug("File [" + fileName
613                             + "] will just be moved as it is not a valid type");
614                 }
615                 return false;
616             }
617         }
618         return true;
619     }
620 
621     /**
622      * Escapes the search token so it is fit for a regex replacement
623      *
624      * @return true if the file is a valid type, else false
625      */
626     private String escape(String str) {
627         String newStr = "";
628         char[] strArr = str.toCharArray();
629 
630         for (int i = 0; i < strArr.length; i++) {
631             if (strArr[i] == '.') {
632                 newStr += "\\";
633             }
634             if (strArr[i] == '\\') {
635                 newStr += "\\";
636             }
637             newStr += strArr[i];
638         }
639 
640         if (debug) {
641             log.debug("escaped str is [" + newStr + "]");
642         }
643 
644         return newStr;
645     }
646 
647     /**
648      * This method changes the name of any strings in the file and saves the
649      * file back to disk
650      * <p/>
651      * With paths, there may be both \ path delimiters or / so we need to run
652      * the regex twice to ensure we have replaced both types
653      *
654      * @return the contents of the file after the package names have been
655      *         changed
656      */
657     private String changePackagePaths(String fileContents) {
658         String output = changeWindowsPaths(fileContents);
659         output = changeUnixPaths(output);
660         return output;
661     }
662 
663     /**
664      * This method changes the name of any strings in the file and saves the
665      * file back to disk
666      * <p/>
667      * With paths, there may be both \ path delimiters or / so we need to run
668      * the regex twice to ensure we have replaced both types
669      *
670      * @return the contents of the file after the package names have been
671      *         changed
672      */
673     private String changeUnixPaths(String fileContents) {
674         if (debug) {
675             log.debug("inside changeUnixPaths");
676         }
677 
678         String patternStr;
679 
680         if (newPkgPath.length() == 0) {
681             patternStr = getUnixPath(existingPkgPath) + "/";
682         } else {
683             if (debug) {
684                 log.debug("before calling getUnixPath existingPkgPath is ["
685                         + existingPkgPath + "]");
686             }
687 
688             patternStr = getUnixPath(existingPkgPath);
689         }
690 
691         if (debug) {
692             log.debug("patternStr before escaping is [" + patternStr + "]");
693         }
694 
695         patternStr = escape(patternStr);
696 
697         if (debug) {
698             log.debug("after escaping the search/match string is [" + patternStr
699                     + "]");
700             log.debug("newPkgPath is [" + newPkgPath + "] about to escape it");
701         }
702 
703         String replacementStr = escape(getUnixPath(newPkgPath));
704 
705         if (debug) {
706             log.debug("replacementStr after escaping is [" + replacementStr + "]");
707         }
708 
709         return performReplacement(fileContents, patternStr, replacementStr);
710     }
711 
712     /**
713      * This method replaces any UNIX style path separators for Windows style
714      * separators
715      *
716      * @return the path
717      */
718     private String getWindowsPath(String path) {
719         String newStr = "";
720         char[] strArr = path.toCharArray();
721 
722         for (int i = 0; i < strArr.length; i++) {
723             if (strArr[i] == '/') {
724                 newStr += "\\";
725             } else {
726                 newStr += strArr[i];
727             }
728         }
729 
730         if (debug) {
731             log.debug("escaped str is [" + newStr + "]");
732         }
733 
734         return newStr;
735     }
736 
737     /**
738      * This method replaces any Windows style path separators for UNIX style
739      * separators
740      *
741      * @return the path
742      */
743     private String getUnixPath(String path) {
744         if (debug) {
745             log.debug("inside getUnixPath with path [" + path + "]");
746         }
747 
748         String newStr = "";
749         char[] strArr = path.toCharArray();
750 
751         for (int i = 0; i < strArr.length; i++) {
752             if (strArr[i] == '\\') {
753                 newStr += "/";
754             } else {
755                 newStr += strArr[i];
756             }
757         }
758 
759         if (debug) {
760             log.debug("escaped str is [" + newStr + "]");
761         }
762 
763         return newStr;
764     }
765 
766     /**
767      * This method changes the name of any strings in the file and saves the
768      * file back to disk
769      * <p/>
770      * With paths, there may be both \ path delimiters or / so we need to run
771      * the regex twice to ensure we have replaced both types
772      *
773      * @return the contents of the file after the package names have been
774      *         changed
775      */
776     private String changeWindowsPaths(String fileContents) {
777         if (debug) {
778             log.debug("inside changeWindowsPaths");
779         }
780 
781         String patternStr;
782 
783         if (newPkgPath.length() == 0) {
784             patternStr = getWindowsPath(existingPkgPath) + "\\";
785         } else {
786             if (debug) {
787                 log.debug("existingPkgPath is currently [" + existingPkgPath
788                         + "] before calling getWindowsPath");
789             }
790 
791             patternStr = getWindowsPath(existingPkgPath);
792 
793         }
794 
795         if (debug) {
796             log.debug("patternStr is [" + patternStr
797                     + "] after calling getWindowsPath");
798         }
799 
800         patternStr = escape(patternStr);
801 
802         if (debug) {
803             log.debug("After escaping the pattern/search str it is [" + patternStr
804                     + "]");
805             log.debug("Before escaping and calling getWindowsPath the newPkgPath it is ["
806                     + newPkgPath + "]");
807         }
808 
809         String replacementStr = escape(getWindowsPath(newPkgPath));
810 
811         if (debug) {
812             log.debug("After escaping it, it is now [" + replacementStr + "]");
813         }
814 
815         return performReplacement(fileContents, patternStr, replacementStr);
816     }
817 
818     /**
819      * This method changes the name of any strings in the file and saves the
820      * file back to disk
821      * <p/>
822      * With paths, there may be both \ path delimiters or / so we need to run
823      * the regex twice to ensure we have replaced both types
824      *
825      * @return the contents of the file after the package names have been
826      *         changed
827      */
828     private String performReplacement(String fileContents, String patternStr,
829                                       String replacementStr) {
830         if (debug) {
831             log.debug("replacing [" + patternStr + "] with [" + replacementStr + "]");
832         }
833 
834         // Compile regular expression
835         Pattern pattern = Pattern.compile(patternStr);
836 
837         // Replace all occurrences of pattern in input
838         Matcher matcher = pattern.matcher(fileContents);
839         String output = matcher.replaceAll(replacementStr);
840 
841         /*
842          * if (debug) { debug("output is [" + output + "]"); }
843          */
844         return output;
845     }
846 
847     /**
848      * This method changes the name of any strings in the file and saves the
849      * file back to disk
850      *
851      * @return the contents of the file after the package names have been
852      *         changed
853      */
854     private String changePackageNames(String fileContents) {
855         String patternStr;
856 
857         if (newPkgName.length() == 0) {
858             patternStr = existingPkgName + ".";
859         } else {
860             patternStr = existingPkgName;
861         }
862         patternStr = escape(patternStr);
863 
864         String replacementStr = escape(newPkgName);
865 
866         return performReplacement(fileContents, patternStr, replacementStr);
867     }
868 
869     /**
870      * This method changes the name of any strings in the file and saves the
871      * file back to disk
872      *
873      * @return the contents of the file after the package names have been
874      *         changed
875      */
876     private String changePackageNamesInFile(String fileName,
877                                             boolean saveToSameFile) throws IOException {
878         if (debug) {
879             log.debug("calling fromFile with fileName [" + fileName + "]");
880         }
881 
882         String inputStr = fromFile(fileName);
883 
884         String output = changePackageNames(inputStr);
885         output = changePackagePaths(output);
886 
887         if (saveToSameFile) {
888             if (debug) {
889                 log.debug("replaced package names in file and now saving it to ["
890                         + fileName + "]");
891             }
892             toFile(fileName, output);
893         }
894 
895         return output;
896     }
897 
898     /**
899      * This method corrects the File separators on the file name
900      *
901      * @return the correct path to the file
902      */
903     private String correctFileSeparators(String fileName) {
904         String localSeparator = File.separator;
905 
906         if (localSeparator.equals("\\")) {
907             return fileName.replace('/', '\\');
908         } else {
909             return fileName.replace('\\', '/');
910         }
911     }
912 
913     /**
914      * This method changes the name of any strings in the file and saves the
915      * file back to disk, the difference is, it uses Spring Ant-style paths
916      * to load the files
917      */
918     private void renameOtherFiles() {
919         if (debug) {
920             log.debug("Inside renameOtherFiles");
921         }
922 
923         try {
924             for (Iterator itFSets = filesets.iterator(); itFSets.hasNext();) {
925                 FileSet fs = (FileSet) itFSets.next();
926                 fs.setDir(new File(workBaseDir));
927 
928                 if (debug) {
929                     log.debug("got fileset fs [" + fs + "]");
930                 }
931 
932                 DirectoryScanner ds = fs.getDirectoryScanner(new org.apache.tools.ant.Project());
933 
934                 if (debug) {
935                     log.debug("ds baseDir is [" + ds.getBasedir().getAbsolutePath() + "]");
936                 }
937 
938                 ds.scan();
939                 String[] includedFiles = ds.getIncludedFiles();
940 
941                 if (debug) {
942                     log.debug("Got includedFiles [" + includedFiles + "]");
943                 }
944 
945                 if (includedFiles != null) {
946                     for (int i = 0; i < includedFiles.length; i++) {
947                         processOtherFile(includedFiles[i]);
948                     }
949                 } else {
950                     if (debug) {
951                         log.debug("Did not find any matching files for one of the filesets");
952                     }
953 
954                 }
955             }
956         }
957         catch (Exception e) {
958             log.error("Exception at end of renaming other files [" + e.getMessage()
959                     + "]");
960         }
961     }
962 
963     /**
964      * This method changes paths and package names in the given file
965      */
966 
967     private void processOtherFile(String fileName) {
968         try {
969             if (debug) {
970                 log.debug("Processing file [" + fileName + "]");
971             }
972 
973             if (isValidFileType(fileName)) {
974                 fileName = correctFileSeparators(fileName);
975 
976                 if (debug) {
977                     log.debug("After correcting file separators fileName is ["
978                             + fileName + "]");
979                     log.debug("file is valid so changing package names");
980                 }
981 
982                 fileName = workBaseDir + File.separator + fileName;
983                 changePackageNamesInFile(fileName,
984                         RenamePackages.SAVE_FILE);
985 
986                 if (debug) {
987                     log.debug("processing change package names on other file ["
988                             + fileName + "]");
989                 }
990             } else {
991                 log.error("Not processing file [" + fileName + "] as it is not a valid type");
992             }
993         }
994         catch (FileNotFoundException f) {
995             // continue and process next
996             log.error("could not find resource from path ["
997                     + fileName
998                     + "]");
999         }
1000         catch (IOException e) {
1001             log.error("IOException when renaming other files [" + e.getMessage() + "]");
1002         }
1003     }
1004 
1005     /**
1006      * This method removes directory structures
1007      */
1008     public void deleteAll(String fileName) {
1009 
1010         File aFile = new File(fileName);
1011 
1012         if (debug) {
1013             log.debug("inside deleteAll with fileName [" + fileName + "]");
1014         }
1015 
1016         if (aFile.exists()) {
1017             boolean isDir = aFile.isDirectory();
1018             if (isDir) {
1019                 String[] inFiles = aFile.list();
1020 
1021                 for (int fileNum = 0; fileNum < inFiles.length; fileNum++) {
1022                     String subFileName = fileName + File.separator
1023                             + inFiles[fileNum];
1024                     deleteAll(subFileName);
1025                 }
1026             }
1027 
1028             if (debug) {
1029                 log.debug("About to delete file inside deleteAll [" + fileName + "]");
1030             }
1031 
1032             if (aFile.delete()) {
1033                 if (debug) {
1034                     if (isDir) {
1035                         log.debug("Deleted dir [" + fileName + "]");
1036                     } else {
1037                         log.debug("Deleted file [" + fileName + "]");
1038                     }
1039                 }
1040             } else {
1041                 log.error("Failed to delete file/dir [" + fileName + "]");
1042             }
1043         }
1044     }
1045 
1046     private void refactorNonPackageFiles() {
1047 
1048         try {
1049             String[] extensions = {"java", "page", "application", "properties", "tld", "xml"};
1050 
1051             Iterator filesInMain = FileUtils.iterateFiles(new File(this.workBaseDir), extensions, true);
1052 
1053             while (filesInMain.hasNext()) {
1054                 File f = (File) filesInMain.next();
1055                 changePackageNamesInFile(f.getAbsolutePath(), RenamePackages.SAVE_FILE);
1056             }
1057 
1058         } catch (IOException ioex) {
1059             log.error("IOException: " + ioex.getMessage());
1060         }
1061     }
1062 
1063     /**
1064      * This is the main method that gets invoked when ANT calls this task
1065      */
1066     public void execute() {
1067         try {
1068 
1069             if (newPkgName == null) {
1070                 throw new BuildException(
1071                         "The new package path needs to be set using <renamepackages "
1072                                 + "newPkgName=\"${new.pkg.name}\"");
1073             }
1074 
1075             if (baseDir == null) {
1076                 throw new BuildException(
1077                         "The base directory needs to be set using <renamepackages "
1078                                 + "baseDir=\"${src.base.dir}\"/>\n");
1079             }
1080 
1081             if (debug) {
1082                 log.info("existingPkgName is [" + this.existingPkgName + "]");
1083                 log.info("newPkgName is [" + this.newPkgName + "]");
1084             }
1085 
1086             setPackagePaths();
1087 
1088             if (debug) {
1089                 log.info("Package paths set");
1090             }
1091 
1092             repackage(this.baseDir, this.workBaseDir);
1093 
1094             if (debug) {
1095                 log.info("RePackage directories");
1096             }
1097 
1098             renameOtherFiles();
1099 
1100             if (debug) {
1101                 log.info("Rename other files");
1102             }
1103 
1104             // fix files with qualified names other than old package
1105             refactorNonPackageFiles();
1106 
1107             // Check the new dir structures for any files left over with the old pkg name in
1108             checkSummary(this.workBaseDir);
1109 
1110             if (debug) {
1111                 log.info("CheckSummary");
1112             }
1113 
1114             deleteAll(this.baseDir);
1115 
1116             if (debug) {
1117                 log.info("Delete all");
1118             }
1119 
1120             File workBaseDir = new File(this.workBaseDir);
1121             if (workBaseDir.renameTo(new File(this.baseDir))) {
1122                 if (debug) {
1123                     log.info("Successfully renamed work dir back to base dir");
1124                 }
1125             } else {
1126                 log.error("Error could not rename work dir");
1127             }
1128 
1129             // delete src/**/java/org if it exists
1130             deleteOrgPackage("main");
1131             deleteOrgPackage("test");
1132         }
1133         catch (IOException ioe) {
1134             log.error("Caught an IO:" + ioe.getMessage());
1135         }
1136         catch (Exception e) {
1137             log.error("Uncaught exception caught [" + e.getMessage() + "]");
1138         }
1139 
1140         // success!
1141         log.info("[AppFuse] Refactored all 'org.appfuse' packages and paths to '" + newPkgName + "'.");
1142     }
1143 
1144     private void deleteOrgPackage(String path) {
1145         File orgDir = new File(baseDir + "/" + path + "/java/org");
1146         if (orgDir.isDirectory() && orgDir.list().length == 0) {
1147             if (!orgDir.delete()) {
1148                 log.warn("Failed to delete '" + orgDir.getAbsolutePath() + "', please delete manually.");
1149             }
1150         }
1151     }
1152 
1153 }
1154