View Javadoc

1   /***
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.cpd;
5   
6   import net.sourceforge.pmd.SourceFileSelector;
7   
8   import java.io.File;
9   import java.io.FileNotFoundException;
10  import java.io.IOException;
11  import java.util.HashMap;
12  import java.util.HashSet;
13  import java.util.Iterator;
14  import java.util.List;
15  import java.util.Map;
16  import java.util.Set;
17  
18  public class CPD {
19  
20      private Map source = new HashMap();
21      private CPDListener listener = new CPDNullListener();
22      private Tokens tokens = new Tokens();
23      private int minimumTileSize;
24      private MatchAlgorithm matchAlgorithm;
25      private Language language;
26      private boolean skipDuplicates;
27  
28      public CPD(int minimumTileSize, Language language) {
29          this.minimumTileSize = minimumTileSize;
30          this.language = language;
31      }
32  
33      public void skipDuplicates() {
34          this.skipDuplicates = true;
35      }
36  
37      public void setCpdListener(CPDListener cpdListener) {
38          this.listener = cpdListener;
39      }
40  
41      public void go() {
42          TokenEntry.clearImages();
43          matchAlgorithm = new MatchAlgorithm(source, tokens, minimumTileSize, listener);
44          matchAlgorithm.findMatches();
45      }
46  
47      public Iterator getMatches() {
48          return matchAlgorithm.matches();
49      }
50  
51      public void add(File file) throws IOException {
52          add(1, file);
53      }
54  
55      public void addAllInDirectory(String dir) throws IOException {
56          addDirectory(dir, false);
57      }
58  
59      public void addRecursively(String dir) throws IOException {
60          addDirectory(dir, true);
61      }
62  
63      public void add(List files) throws IOException {
64          for (Iterator i = files.iterator(); i.hasNext();) {
65              add(files.size(), (File) i.next());
66          }
67      }
68  
69      private void addDirectory(String dir, boolean recurse) throws IOException {
70          if (!(new File(dir)).exists()) {
71              throw new FileNotFoundException("Couldn't find directory " + dir);
72          }
73          FileFinder finder = new FileFinder();
74          // TODO - could use SourceFileSelector here
75          add(finder.findFilesFrom(dir, language.getFileFilter(), recurse));
76      }
77  
78      private Set current = new HashSet();
79  
80      private void add(int fileCount, File file) throws IOException {
81  
82          if (skipDuplicates) {
83              // TODO refactor this thing into a separate class
84              String signature = file.getName() + "_" + String.valueOf(file.length());
85              if (current.contains(signature)) {
86                  System.out.println("Skipping " + file.getAbsolutePath() + " since it appears to be a duplicate file and --skip-duplicate-files is set");
87                  return;
88              }
89              current.add(signature);
90          }
91  
92          listener.addedFile(fileCount, file);
93          SourceCode sourceCode = new SourceCode(new SourceCode.FileCodeLoader(file));
94          language.getTokenizer().tokenize(sourceCode, tokens);
95          source.put(sourceCode.getFileName(), sourceCode);
96      }
97  
98      public static Renderer getRendererFromString(String name) {
99          if (name.equals("text") || name.equals("")) {
100             return new SimpleRenderer();
101         }
102         try {
103             return (Renderer) Class.forName(name).newInstance();
104         } catch (Exception e) {
105             System.out.println("Can't find class '" + name + "' so defaulting to SimpleRenderer.");
106         }
107         return new SimpleRenderer();
108     }
109 
110     private static boolean findBooleanSwitch(String[] args, String name) {
111         for (int i = 0; i < args.length; i++) {
112             if (args[i].equals(name)) {
113                 return true;
114             }
115         }
116         return false;
117     }
118 
119     private static String findRequiredStringValue(String[] args, String name) {
120         for (int i = 0; i < args.length; i++) {
121             if (args[i].equals(name)) {
122                 return args[i + 1];
123             }
124         }
125         System.out.println("No " + name + " value passed in");
126         usage();
127         throw new RuntimeException();
128     }
129 
130     private static String findOptionalStringValue(String[] args, String name, String defaultValue) {
131         for (int i = 0; i < args.length; i++) {
132             if (args[i].equals(name)) {
133                 return args[i + 1];
134             }
135         }
136         return defaultValue;
137     }
138 
139     public static void main(String[] args) {
140         if (args.length == 0) {
141             usage();
142         }
143 
144         try {
145             boolean skipDuplicateFiles = findBooleanSwitch(args, "--skip-duplicate-files");
146             String pathToFiles = findRequiredStringValue(args, "--files");
147             String languageString = findOptionalStringValue(args, "--language", "java");
148             String formatString = findOptionalStringValue(args, "--format", "text");
149             int minimumTokens = Integer.parseInt(findRequiredStringValue(args, "--minimum-tokens"));
150             LanguageFactory f = new LanguageFactory();
151             Language language = f.createLanguage(languageString);
152             Renderer renderer = CPD.getRendererFromString(formatString);
153             CPD cpd = new CPD(minimumTokens, language);
154             if (skipDuplicateFiles) {
155                 cpd.skipDuplicates();
156             }
157             cpd.addRecursively(pathToFiles);
158             cpd.go();
159             System.out.println(renderer.render(cpd.getMatches()));
160         } catch (Exception e) {
161             e.printStackTrace();
162         }
163     }
164 
165     private static void usage() {
166         System.out.println("Usage:");
167         System.out.println(" java net.sourceforge.pmd.cpd.CPD --minimum-tokens xxx --files xxx [--language xxx] [--format (xml|text|csv)] [--skip-duplicate-files] ");
168         System.out.println("i.e: ");
169         System.out.println(" java net.sourceforge.pmd.cpd.CPD --minimum-tokens 100 --files c://jdk14//src//java ");
170         System.out.println("or: ");
171         System.out.println(" java net.sourceforge.pmd.cpd.CPD --minimum-tokens 100 --files /path/to/c/code --language c ");
172         System.out.println("or: ");
173         System.out.println(" java net.sourceforge.pmd.cpd.CPD --minimum-tokens 100 --files /path/to/java/code --format xml");
174     }
175 
176 }