1
2
3
4 package net.sourceforge.pmd.cpd;
5
6 import java.io.File;
7 import java.io.FileNotFoundException;
8 import java.io.IOException;
9 import java.util.ArrayList;
10 import java.util.HashSet;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Set;
15 import java.util.TreeMap;
16 import java.util.logging.Level;
17 import java.util.logging.Logger;
18
19 import net.sourceforge.pmd.lang.ast.TokenMgrError;
20 import net.sourceforge.pmd.util.FileFinder;
21 import net.sourceforge.pmd.util.database.DBMSMetadata;
22 import net.sourceforge.pmd.util.database.DBURI;
23 import net.sourceforge.pmd.util.database.SourceObject;
24
25 import org.apache.commons.io.FilenameUtils;
26
27 public class CPD {
28 private final static Logger LOGGER = Logger.getLogger(CPD.class.getName());
29
30 private CPDConfiguration configuration;
31
32 private Map<String, SourceCode> source = new TreeMap<String, SourceCode>();
33 private CPDListener listener = new CPDNullListener();
34 private Tokens tokens = new Tokens();
35 private MatchAlgorithm matchAlgorithm;
36
37 public CPD(CPDConfiguration theConfiguration) {
38 configuration = theConfiguration;
39
40 TokenEntry.clearImages();
41 }
42
43 public void setCpdListener(CPDListener cpdListener) {
44 this.listener = cpdListener;
45 }
46
47 public void go() {
48 matchAlgorithm = new MatchAlgorithm(source, tokens,configuration.getMinimumTileSize(),listener);
49 matchAlgorithm.findMatches();
50 }
51
52 public Iterator<Match> getMatches() {
53 return matchAlgorithm.matches();
54 }
55
56 public void addAllInDirectory(File dir) throws IOException {
57 addDirectory(dir, false);
58 }
59
60 public void addRecursively(File dir) throws IOException {
61 addDirectory(dir, true);
62 }
63
64 public void add(List<File> files) throws IOException {
65 for (File f: files) {
66 add(f);
67 }
68 }
69
70 private void addDirectory(File dir, boolean recurse) throws IOException {
71 if (!dir.exists()) {
72 throw new FileNotFoundException("Couldn't find directory " + dir);
73 }
74 FileFinder finder = new FileFinder();
75
76 add(finder.findFilesFrom(dir, configuration.filenameFilter(), recurse));
77 }
78
79 private Set<String> current = new HashSet<String>();
80
81 public void add(File file) throws IOException {
82
83 if (configuration.isSkipDuplicates()) {
84
85 String signature = file.getName() + '_' + file.length();
86 if (current.contains(signature)) {
87 System.err.println("Skipping " + file.getAbsolutePath() + " since it appears to be a duplicate file and --skip-duplicate-files is set");
88 return;
89 }
90 current.add(signature);
91 }
92
93 if (!FilenameUtils.equalsNormalizedOnSystem(file.getAbsoluteFile().getCanonicalPath(), file.getAbsolutePath())) {
94 System.err.println("Skipping " + file + " since it appears to be a symlink");
95 return;
96 }
97
98 if (!file.exists()) {
99 System.err.println("Skipping " + file + " since it doesn't exist (broken symlink?)");
100 return;
101 }
102
103 SourceCode sourceCode = configuration.sourceCodeFor(file);
104 add(sourceCode);
105 }
106
107 public void add(DBURI dburi) throws IOException {
108
109 try
110 {
111 DBMSMetadata dbmsmetadata = new DBMSMetadata(dburi) ;
112
113 List<SourceObject> sourceObjectList = dbmsmetadata.getSourceObjectList ();
114 LOGGER.log(Level.FINER, "Located {0} database source objects", sourceObjectList.size());
115
116 for (SourceObject sourceObject: sourceObjectList )
117 {
118
119 String falseFilePath = sourceObject.getPseudoFileName();
120 LOGGER.log(Level.FINEST, "Adding database source object {0}", falseFilePath);
121
122 SourceCode sourceCode = configuration.sourceCodeFor( dbmsmetadata.getSourceCode(sourceObject)
123 ,falseFilePath
124 );
125 add(sourceCode);
126 }
127 }
128 catch (Exception sqlException)
129 {
130 LOGGER.log(Level.SEVERE, "Problem with Input URI", sqlException);
131 throw new RuntimeException("Problem with DBURI: "+dburi , sqlException ) ;
132 }
133 }
134
135 private void add(SourceCode sourceCode) throws IOException {
136 if (configuration.isSkipLexicalErrors()) {
137 addAndSkipLexicalErrors(sourceCode);
138 } else {
139 addAndThrowLexicalError(sourceCode);
140 }
141 }
142
143 private void addAndThrowLexicalError(SourceCode sourceCode) throws IOException {
144 configuration.tokenizer().tokenize(sourceCode, tokens);
145 listener.addedFile(1, new File(sourceCode.getFileName()));
146 source.put(sourceCode.getFileName(), sourceCode);
147 }
148
149 private void addAndSkipLexicalErrors(SourceCode sourceCode) throws IOException {
150 TokenEntry.State savedTokenEntry = new TokenEntry.State(tokens.getTokens());
151 try {
152 addAndThrowLexicalError(sourceCode);
153 } catch (TokenMgrError e) {
154 System.err.println("Skipping " + sourceCode.getFileName() + ". Reason: " + e.getMessage());
155 tokens.getTokens().clear();
156 tokens.getTokens().addAll(savedTokenEntry.restore());
157 }
158 }
159
160
161
162
163
164
165 public List<String> getSourcePaths() {
166 return new ArrayList<String>(source.keySet());
167 }
168
169
170
171
172
173
174 public List<SourceCode> getSources() {
175 return new ArrayList<SourceCode>(source.values());
176 }
177
178
179 public static void main(String[] args) {
180 CPDCommandLineInterface.main(args);
181 }
182 }