001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2011 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * Sonar is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020 021 /** 022 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html 023 */ 024 package org.sonar.duplications.cpd; 025 026 import net.sourceforge.pmd.cpd.*; 027 import net.sourceforge.pmd.util.FileFinder; 028 029 import java.io.File; 030 import java.io.FileNotFoundException; 031 import java.io.IOException; 032 import java.util.HashMap; 033 import java.util.Iterator; 034 import java.util.List; 035 import java.util.Map; 036 037 public class CPD { 038 039 private Map<String, SourceCode> source = new HashMap<String, SourceCode>(); 040 private CPDListener listener = new CPDNullListener(); 041 private Tokens tokens = new Tokens(); 042 private int minimumTileSize; 043 private MatchAlgorithm matchAlgorithm; 044 private Language language; 045 private boolean loadSourceCodeSlices = true; 046 private String encoding = System.getProperty("file.encoding"); 047 048 public CPD(int minimumTileSize, Language language) { 049 TokenEntry.clearImages(); // workaround for bug 1947823 050 this.minimumTileSize = minimumTileSize; 051 this.language = language; 052 } 053 054 public void setCpdListener(CPDListener cpdListener) { 055 this.listener = cpdListener; 056 } 057 058 public void setEncoding(String encoding) { 059 this.encoding = encoding; 060 } 061 062 public void setLoadSourceCodeSlices(boolean loadSourceCodeSlices) { 063 this.loadSourceCodeSlices = loadSourceCodeSlices; 064 } 065 066 public void go() { 067 TokenEntry.clearImages(); 068 matchAlgorithm = new MatchAlgorithm(source, tokens, minimumTileSize, listener); 069 matchAlgorithm.setLoadSourceCodeSlices(loadSourceCodeSlices); 070 matchAlgorithm.findMatches(); 071 } 072 073 public Iterator<Match> getMatches() { 074 return matchAlgorithm.matches(); 075 } 076 077 public void add(File file) throws IOException { 078 add(1, file); 079 } 080 081 public void addAllInDirectory(String dir) throws IOException { 082 addDirectory(dir, false); 083 } 084 085 public void addRecursively(String dir) throws IOException { 086 addDirectory(dir, true); 087 } 088 089 public void add(List<File> files) throws IOException { 090 for (File f : files) { 091 add(files.size(), f); 092 } 093 } 094 095 private void addDirectory(String dir, boolean recurse) throws IOException { 096 if (!(new File(dir)).exists()) { 097 throw new FileNotFoundException("Couldn't find directory " + dir); 098 } 099 FileFinder finder = new FileFinder(); 100 // TODO - could use SourceFileSelector here 101 add(finder.findFilesFrom(dir, language.getFileFilter(), recurse)); 102 } 103 104 private void add(int fileCount, File file) throws IOException { 105 if (!file.getCanonicalPath().equals(new File(file.getAbsolutePath()).getCanonicalPath())) { 106 System.out.println("Skipping " + file + " since it appears to be a symlink"); 107 return; 108 } 109 110 listener.addedFile(fileCount, file); 111 SourceCode sourceCode = new SourceCode(new FileCodeLoaderWithoutCache(file, encoding)); 112 language.getTokenizer().tokenize(sourceCode, tokens); 113 source.put(sourceCode.getFileName(), sourceCode); 114 } 115 116 117 }