日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

sonar findbugs plugin源码研究

發(fā)布時(shí)間:2023/12/19 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 sonar findbugs plugin源码研究 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

首先貼一下findbugs plugin 代碼目錄:


代碼:



代碼里面有很幾個(gè)關(guān)于plugin定義的關(guān)鍵類:

language包下面定義了掃描jsp 的思路:

public class Jspextends AbstractLanguage {public static final String KEY = "jsp";public static final String NAME = "JSP";public static final String FILE_SUFFIXES_KEY = "sonar.jsp.file.suffixes";public static final String DEFAULT_FILE_SUFFIXES = ".jsp";private final Settings settings;public Jsp(Settings settings){super("jsp", "JSP");this.settings = settings;}public String[] getFileSuffixes(){String[] suffixes = filterEmptyStrings(this.settings.getStringArray("sonar.jsp.file.suffixes"));if (suffixes.length == 0) {suffixes = StringUtils.split(".jsp", ",");}return suffixes;}private static String[] filterEmptyStrings(String[] stringArray){List<String> nonEmptyStrings = Lists.newArrayList();for (String string : stringArray) {if (StringUtils.isNotBlank(string.trim())) {nonEmptyStrings.add(string.trim());}}return (String[])nonEmptyStrings.toArray(new String[nonEmptyStrings.size()]);} }

JspCodeColorizerFormat 類定義了如何識(shí)別標(biāo)簽掃描jsp

public class JspCodeColorizerFormatextends CodeColorizerFormat {private final List<Tokenizer> tokenizers = new ArrayList();public JspCodeColorizerFormat(){super("jsp");String tagAfter = "</span>";this.tokenizers.add(new RegexpTokenizer("<span class=\"k\">", tagAfter, "</?[:\\w]+>?"));this.tokenizers.add(new RegexpTokenizer("<span class=\"k\">", tagAfter, ">"));this.tokenizers.add(new RegexpTokenizer("<span class=\"j\">", tagAfter, "<!DOCTYPE.*>"));this.tokenizers.add(new MultilinesDocTokenizer("<!--", "-->", "<span class=\"j\">", tagAfter));this.tokenizers.add(new MultilinesDocTokenizer("<%--", "--%>", "<span class=\"j\">", tagAfter));this.tokenizers.add(new MultilinesDocTokenizer("<%@", "%>", "<span class=\"a\">", tagAfter));this.tokenizers.add(new MultilinesDocTokenizer("<%", "%>", "<span class=\"a\">", tagAfter));this.tokenizers.add(new StringTokenizer("<span class=\"s\">", tagAfter));}public List<Tokenizer> getTokenizers(){return this.tokenizers;} }

profiles 包中定義了規(guī)則相關(guān):

FindBugs + FB-Contrib 規(guī)則,針對(duì)語(yǔ)言java

public class FindbugsContribProfileextends ProfileDefinition {private static final String FB_CONTRIB_PROFILE_NAME = "FindBugs + FB-Contrib";private final FindbugsProfileImporter importer;public FindbugsContribProfile(FindbugsProfileImporter importer){this.importer = importer;}public RulesProfile createProfile(ValidationMessages messages){Reader findbugsProfile = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/plugins/findbugs/profile-findbugs-and-fb-contrib.xml"));RulesProfile profile = this.importer.importProfile(findbugsProfile, messages);profile.setLanguage("java");profile.setName("FindBugs + FB-Contrib");return profile;} }

定義FindBugs 規(guī)則,針對(duì)語(yǔ)言java

public class FindbugsProfileextends ProfileDefinition {private static final String FINDBUGS_PROFILE_NAME = "FindBugs";private final FindbugsProfileImporter importer;public FindbugsProfile(FindbugsProfileImporter importer){this.importer = importer;}public RulesProfile createProfile(ValidationMessages messages){Reader findbugsProfile = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/plugins/findbugs/profile-findbugs-only.xml"));RulesProfile profile = this.importer.importProfile(findbugsProfile, messages);profile.setLanguage("java");profile.setName("FindBugs");return profile;} }

定義了規(guī)則FindBugs Security Audit,針對(duì)語(yǔ)言java

public class FindbugsSecurityAuditProfileextends ProfileDefinition {private static final String FINDBUGS_SECURITY_AUDIT_PROFILE_NAME = "FindBugs Security Audit";private final FindbugsProfileImporter importer;public FindbugsSecurityAuditProfile(FindbugsProfileImporter importer){this.importer = importer;}public RulesProfile createProfile(ValidationMessages messages){Reader findbugsProfile = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/plugins/findbugs/profile-findbugs-security-audit.xml"));RulesProfile profile = this.importer.importProfile(findbugsProfile, messages);profile.setLanguage("java");profile.setName("FindBugs Security Audit");return profile;} }

定義檢查規(guī)則FindBugs Security JSP 針對(duì)語(yǔ)言:jsp

public class FindbugsSecurityJspProfileextends ProfileDefinition {private static final String FINDBUGS_SECURITY_JSP_PROFILE_NAME = "FindBugs Security JSP";private final FindbugsProfileImporter importer;public FindbugsSecurityJspProfile(FindbugsProfileImporter importer){this.importer = importer;}public RulesProfile createProfile(ValidationMessages messages){Reader findbugsProfile = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/plugins/findbugs/profile-findbugs-security-jsp.xml"));RulesProfile profile = this.importer.importProfile(findbugsProfile, messages);profile.setLanguage("jsp");profile.setName("FindBugs Security JSP");return profile;}

定義規(guī)則:FindBugs Security Minimal 針對(duì)語(yǔ)言java

public class FindbugsSecurityMinimalProfileextends ProfileDefinition {private static final String FINDBUGS_SECURITY_AUDIT_PROFILE_NAME = "FindBugs Security Minimal";private final FindbugsProfileImporter importer;public FindbugsSecurityMinimalProfile(FindbugsProfileImporter importer){this.importer = importer;}public RulesProfile createProfile(ValidationMessages messages){Reader findbugsProfile = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/plugins/findbugs/profile-findbugs-security-minimal.xml"));RulesProfile profile = this.importer.importProfile(findbugsProfile, messages);profile.setLanguage("java");profile.setName("FindBugs Security Minimal");return profile;} }

resource包下面定義的類,是加載掃描jsp 相關(guān)java類

public class ByteCodeResourceLocatorimplements BatchExtension {private static final Logger LOG = LoggerFactory.getLogger(ByteCodeResourceLocator.class);private static final String[] SOURCE_DIRECTORIES = { "src/main/java", "src/main/webapp", "src/main/resources", "src", "/src/java" };public InputFile findJavaClassFile(String className, FileSystem fs){int indexDollarSign = className.indexOf("$");if (indexDollarSign != -1) {className = className.substring(0, indexDollarSign);}return buildInputFile(className.replaceAll("\\.", "/") + ".java", fs);}public InputFile findJavaOuterClassFile(String className, File classFile, FileSystem fs){try{InputStream in = new FileInputStream(classFile);Throwable localThrowable4 = null;try{DebugExtensionExtractor debug = new DebugExtensionExtractor();String source = debug.getDebugSourceFromClass(in);if (source == null) {return null;}String newClassName = FilenameUtils.getBaseName(source);String packagePrefix = className.lastIndexOf(".") != -1 ? FilenameUtils.getBaseName(className) + "." : "";String fullClassName = packagePrefix + newClassName;return findJavaClassFile(fullClassName, fs);}catch (Throwable localThrowable2){localThrowable4 = localThrowable2;throw localThrowable2;}finally{if (in != null) {if (localThrowable4 != null) {try{in.close();}catch (Throwable localThrowable3){localThrowable4.addSuppressed(localThrowable3);}} else {in.close();}}}return null;}catch (IOException e){LOG.warn("An error occurs while opening classfile : " + classFile.getPath());}}public InputFile findTemplateFile(String className, FileSystem fs){List<String> potentialJspFilenames = new ArrayList();if (className.startsWith("jsp_servlet")){String jspFile = className.substring(11).replaceFirst("\\.__([^\\.]+)$", "/$1\\.jsp").replace("._", "/");potentialJspFilenames.add(jspFile);}String jspFileFromClass;if (className.endsWith("_jsp")){jspFileFromClass = JasperUtils.decodeJspClassName(className);potentialJspFilenames.add(jspFileFromClass);for (String packageName : Arrays.asList(new String[] { "jsp/", "org/apache/jsp/" })) {if (jspFileFromClass.startsWith(packageName)) {potentialJspFilenames.add(jspFileFromClass.substring(packageName.length()));}}}for (String jspFilename : potentialJspFilenames){InputFile file = buildInputFile(jspFilename, fs);if (file != null) {return file;}}return null;}public InputFile buildInputFile(String fileName, FileSystem fs){for (String sourceDir : SOURCE_DIRECTORIES){Iterable<InputFile> files = fs.inputFiles(fs.predicates().hasRelativePath(sourceDir + "/" + fileName));Iterator localIterator = files.iterator();if (localIterator.hasNext()){InputFile f = (InputFile)localIterator.next();return f;}}return null;}@Nullablepublic SmapParser.SmapLocation extractSmapLocation(String className, int originalLine, File classFile){String smap;try{InputStream in = new FileInputStream(classFile);Throwable localThrowable7 = null;try{DebugExtensionExtractor debug = new DebugExtensionExtractor();smap = debug.getDebugExtFromClass(in);if (smap != null) {return getJspLineNumberFromSmap(smap, Integer.valueOf(originalLine));}}catch (Throwable localThrowable2){localThrowable7 = localThrowable2;throw localThrowable2;}finally{if (in != null) {if (localThrowable7 != null) {try{in.close();}catch (Throwable localThrowable3){localThrowable7.addSuppressed(localThrowable3);}} else {in.close();}}}}catch (IOException e){LOG.warn("An error occurs while opening classfile : " + classFile.getPath());}LOG.debug("No smap file found for the class: " + className);File smapFile = new File(classFile.getPath() + ".smap");if (smapFile.exists()) {try{Object smapInputStream = new FileInputStream(smapFile);localThrowable2 = null;try{return getJspLineNumberFromSmap(IOUtils.toString((InputStream)smapInputStream), Integer.valueOf(originalLine));}catch (Throwable localThrowable5){localThrowable2 = localThrowable5;throw localThrowable5;}finally{if (smapInputStream != null) {if (localThrowable2 != null) {try{((InputStream)smapInputStream).close();}catch (Throwable localThrowable6){localThrowable2.addSuppressed(localThrowable6);}} else {((InputStream)smapInputStream).close();}}}LOG.debug("No smap mapping found.");}catch (IOException e){LOG.debug("Unable to open smap file : " + smapFile.getAbsolutePath());}}return null;}private SmapParser.SmapLocation getJspLineNumberFromSmap(String smap, Integer originalLine)throws IOException{SmapParser parser = new SmapParser(smap);return parser.getSmapLocation(originalLine);} } public class SmapParser {private String javaFilename;private final Map<Integer, FileInfo> fileinfo = new HashMap();private final Map<Integer, int[]> java2jsp = new HashMap();private static final Pattern LINE_INFO_PATTERN = Pattern.compile("([0-9]+)(?:#([0-9]+))?(?:,([0-9]+))?:([0-9]+)(?:,([0-9]+))?");private static String getLine(BufferedReader reader)throws IOException{String s = reader.readLine();if (s == null) {throw new IOException("EOF parsing SMAP");}return s;}public SmapParser(String smap)throws IOException{BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(smap.getBytes())));String header = getLine(reader);this.javaFilename = getLine(reader);String jsp = getLine(reader);String stratum = getLine(reader);String f = getLine(reader);if ((!header.equals("SMAP")) || (!stratum.startsWith("*S ")) || (!f.equals("*F"))) {throw new IllegalArgumentException("Unexpected SMAP file format");}String line;while (((line = getLine(reader)) != null) && (!line.equals("*L"))){String path = null;if (line.startsWith("+ ")){path = getLine(reader);line = line.substring(2);}int pos = line.indexOf(" ");int fileNum = Integer.parseInt(line.substring(0, pos));String name = line.substring(pos + 1);this.fileinfo.put(Integer.valueOf(fileNum), new FileInfo(name, path == null ? name : path));}int lastLFI = 0;while (((line = getLine(reader)) != null) && (!line.equals("*E"))) {if (!line.startsWith("*")){Matcher m = LINE_INFO_PATTERN.matcher(line);if (!m.matches()) {throw new IllegalArgumentException(line);}int inputStartLine = Integer.parseInt(m.group(1));int lineFileID = m.group(2) == null ? lastLFI : Integer.parseInt(m.group(2));int repeatCount = m.group(3) == null ? 1 : Integer.parseInt(m.group(3));int outputStartLine = Integer.parseInt(m.group(4));int outputLineIncrement = m.group(5) == null ? 1 : Integer.parseInt(m.group(5));for (int i = 0; i < repeatCount; i++){int[] inputMapping = { lineFileID, inputStartLine + i };int baseOL = outputStartLine + i * outputLineIncrement;for (int ol = baseOL; ol < baseOL + outputLineIncrement; ol++) {if (!this.java2jsp.containsKey(Integer.valueOf(ol))) {this.java2jsp.put(Integer.valueOf(ol), inputMapping);}}}lastLFI = lineFileID;}}}public String getJavaFilename(){return this.javaFilename;}public String getScriptFilename(int fileIndex){FileInfo f = (FileInfo)this.fileinfo.get(Integer.valueOf(fileIndex));return f.name;}public int[] getScriptLineNumber(Integer lineNo){return (int[])this.java2jsp.get(lineNo);}public SmapLocation getSmapLocation(Integer lineNo){int[] origSource = (int[])this.java2jsp.get(lineNo);FileInfo info = (FileInfo)this.fileinfo.get(Integer.valueOf(origSource[0]));return new SmapLocation(info, origSource[1], origSource[0] == 0);}public static class FileInfo{public final String name;public final String path;public FileInfo(String name, String path){this.name = name;this.path = path;}}public static class SmapLocation{public final SmapParser.FileInfo fileInfo;public final int line;public final boolean isPrimaryFile;public SmapLocation(SmapParser.FileInfo fileInfo, int line, boolean isPrimaryFile){this.fileInfo = fileInfo;this.line = line;this.isPrimaryFile = isPrimaryFile;}} } public static String decodeJspClassName(String className){className = className.replaceAll("\\.", "/");for (char ch = '\000'; ch < ''; ch = (char)(ch + '\001')) {if (((isPrintableChar(ch)) && (!Character.isJavaIdentifierPart(ch))) || (ch == '_')) {className = className.replace(mangleChar(ch), "" + ch);}}return className.replaceAll("_jsp", ".jsp");}public static final String mangleChar(char ch){char[] result = new char[5];result[0] = '_';result[1] = Character.forDigit(ch >> '\f' & 0xF, 16);result[2] = Character.forDigit(ch >> '\b' & 0xF, 16);result[3] = Character.forDigit(ch >> '\004' & 0xF, 16);result[4] = Character.forDigit(ch & 0xF, 16);return new String(result);}public static boolean isPrintableChar(char c){Character.UnicodeBlock block = Character.UnicodeBlock.of(c);return (!Character.isISOControl(c)) && (c != 65535) && (block != null) && (block != Character.UnicodeBlock.SPECIALS);} }

xml 包中定義一些規(guī)則相關(guān)的bean

FindbugsPlugin 定義類:

public class FindbugsPluginimplements Plugin {public void define(Plugin.Context context){context.addExtensions(FindbugsConfiguration.getPropertyDefinitions());context.addExtensions(Arrays.asList(new Class[] { Jsp.class, JspCodeColorizerFormat.class, FindbugsSensor.class, FindbugsConfiguration.class, FindbugsExecutor.class, FindbugsProfileExporter.class, FindbugsProfileImporter.class, FindbugsProfile.class, FindbugsContribProfile.class, FindbugsSecurityAuditProfile.class, FindbugsSecurityMinimalProfile.class, FindbugsSecurityJspProfile.class, FindbugsRulesDefinition.class, FbContribRulesDefinition.class, FindSecurityBugsRulesDefinition.class, FindSecurityBugsJspRulesDefinition.class, ByteCodeResourceLocator.class }));} }

加載各種定義的 profile類,然后就是FindbugsProfileExporter和FindbugsProfileImporter,規(guī)則文件的到處生產(chǎn)和規(guī)則文件的導(dǎo)入類:

FindbugsProfileExporter類:

public class FindbugsProfileExporterextends ProfileExporter {public FindbugsProfileExporter(){super("findbugs", "FindBugs");setSupportedLanguages(new String[] { "java", "jsp" });setMimeType("application/xml");}public void exportProfile(RulesProfile profile, Writer writer){try{FindBugsFilter filter = buildFindbugsFilter(Iterables.concat(profile.getActiveRulesByRepository("findbugs"), profile.getActiveRulesByRepository("fb-contrib"), profile.getActiveRulesByRepository("findsecbugs"), profile.getActiveRulesByRepository("findsecbugs-jsp")));XStream xstream = FindBugsFilter.createXStream();writer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- Generated by SonarQube -->\n".concat(xstream.toXML(filter)));}catch (IOException e){throw new SonarException("Fail to export the Findbugs profile : " + profile, e);}}public static FindBugsFilter buildFindbugsFilter(Iterable<ActiveRule> activeRules){FindBugsFilter root = new FindBugsFilter();for (ActiveRule activeRule : activeRules) {if (("findbugs".equals(activeRule.getRepositoryKey())) || ("fb-contrib".equals(activeRule.getRepositoryKey())) || ("findsecbugs".equals(activeRule.getRepositoryKey())) || ("findsecbugs-jsp".equals(activeRule.getRepositoryKey()))){Match child = new Match();child.setBug(new Bug(activeRule.getConfigKey()));root.addMatch(child);}}return root;} }

FindbugsProfileImporter規(guī)則導(dǎo)入類:

public class FindbugsProfileImporterextends ProfileImporter {private final RuleFinder ruleFinder;private static final Logger LOG = LoggerFactory.getLogger(FindbugsProfileImporter.class);public FindbugsProfileImporter(RuleFinder ruleFinder){super("findbugs", "FindBugs");setSupportedLanguages(new String[] { "java", "jsp" });this.ruleFinder = ruleFinder;}public RulesProfile importProfile(Reader findbugsConf, ValidationMessages messages){RulesProfile profile = RulesProfile.create();try{XStream xStream = FindBugsFilter.createXStream();FindBugsFilter filter = (FindBugsFilter)xStream.fromXML(findbugsConf);activateRulesByCategory(profile, filter, messages);activateRulesByCode(profile, filter, messages);activateRulesByPattern(profile, filter, messages);return profile;}catch (Exception e){String errorMessage = "The Findbugs configuration file is not valid";messages.addErrorText(errorMessage + " : " + e.getMessage());LOG.error(errorMessage, e);}return profile;}private void activateRulesByPattern(RulesProfile profile, FindBugsFilter filter, ValidationMessages messages){for (Map.Entry<String, String> patternLevel : filter.getPatternLevels(new FindbugsLevelUtils()).entrySet()){Rule rule = this.ruleFinder.findByKey("findbugs", (String)patternLevel.getKey());if (rule == null){rule = this.ruleFinder.findByKey("fb-contrib", (String)patternLevel.getKey());if (rule == null){rule = this.ruleFinder.findByKey("findsecbugs", (String)patternLevel.getKey());if (rule == null) {rule = this.ruleFinder.findByKey("findsecbugs-jsp", (String)patternLevel.getKey());}}}if (rule != null) {profile.activateRule(rule, getPriorityFromSeverity((String)patternLevel.getValue()));} else {messages.addWarningText("Unable to activate unknown rule : '" + (String)patternLevel.getKey() + "'");}}}private void activateRulesByCode(RulesProfile profile, FindBugsFilter filter, ValidationMessages messages){for (Map.Entry<String, String> codeLevel : filter.getCodeLevels(new FindbugsLevelUtils()).entrySet()){boolean someRulesHaveBeenActivated = false;for (Rule rule : rules()) {if ((rule.getKey().equals(codeLevel.getKey())) || (StringUtils.startsWith(rule.getKey(), (String)codeLevel.getKey() + "_"))){someRulesHaveBeenActivated = true;profile.activateRule(rule, getPriorityFromSeverity((String)codeLevel.getValue()));}}if (!someRulesHaveBeenActivated) {messages.addWarningText("Unable to find any rules associated to code : '" + (String)codeLevel.getKey() + "'");}}}private void activateRulesByCategory(RulesProfile profile, FindBugsFilter filter, ValidationMessages messages){for (Map.Entry<String, String> categoryLevel : filter.getCategoryLevels(new FindbugsLevelUtils()).entrySet()){boolean someRulesHaveBeenActivated = false;String sonarCateg = FindbugsCategory.findbugsToSonar((String)categoryLevel.getKey());for (Rule rule : rules()) {if ((sonarCateg != null) && (rule.getName().startsWith(sonarCateg))){someRulesHaveBeenActivated = true;profile.activateRule(rule, getPriorityFromSeverity((String)categoryLevel.getValue()));}}if (!someRulesHaveBeenActivated) {messages.addWarningText("Unable to find any rules associated to category : '" + (String)categoryLevel.getKey() + "'");}}}private static RulePriority getPriorityFromSeverity(String severity){if ("INFO".equals(severity)) {return RulePriority.INFO;}if ("MAJOR".equals(severity)) {return RulePriority.MAJOR;}if ("BLOCKER".equals(severity)) {return RulePriority.BLOCKER;}return null;}private Iterable<Rule> rules(){return Iterables.concat(this.ruleFinder.findAll(RuleQuery.create().withRepositoryKey("findbugs")), this.ruleFinder.findAll(RuleQuery.create().withRepositoryKey("fb-contrib")), this.ruleFinder.findAll(RuleQuery.create().withRepositoryKey("findsecbugs")), this.ruleFinder.findAll(RuleQuery.create().withRepositoryKey("findsecbugs-jsp")));} }

然后加載findbugsSensor類:findbugsSensor定義了,各個(gè)profile的引入和掃描jsp文件以及對(duì)應(yīng)的java 的class文件。

package org.sonar.plugins.findbugs;import java.io.File; import java.util.Collection; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.rule.ActiveRule; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.sensor.Sensor; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.SensorDescriptor; import org.sonar.api.batch.sensor.issue.NewIssue; import org.sonar.api.batch.sensor.issue.NewIssueLocation; import org.sonar.api.profiles.RulesProfile; import org.sonar.plugins.findbugs.resource.ByteCodeResourceLocator; import org.sonar.plugins.findbugs.resource.ClassMetadataLoadingException; import org.sonar.plugins.findbugs.resource.SmapParser.FileInfo; import org.sonar.plugins.findbugs.resource.SmapParser.SmapLocation; import org.sonar.plugins.java.api.JavaResourceLocator;public class FindbugsSensorimplements Sensor {private static final Logger LOG = LoggerFactory.getLogger(FindbugsSensor.class);private RulesProfile profile;private ActiveRules ruleFinder;private FindbugsExecutor executor;private final JavaResourceLocator javaResourceLocator;private final ByteCodeResourceLocator byteCodeResourceLocator;private final FileSystem fs;private final SensorContext sensorContext;public FindbugsSensor(RulesProfile profile, ActiveRules ruleFinder, SensorContext sensorContext, FindbugsExecutor executor, JavaResourceLocator javaResourceLocator, FileSystem fs, ByteCodeResourceLocator byteCodeResourceLocator){this.profile = profile;this.ruleFinder = ruleFinder;this.sensorContext = sensorContext;this.executor = executor;this.javaResourceLocator = javaResourceLocator;this.byteCodeResourceLocator = byteCodeResourceLocator;this.fs = fs;}private boolean hasActiveFindbugsRules(){return !this.profile.getActiveRulesByRepository("findbugs").isEmpty();}private boolean hasActiveFbContribRules(){return !this.profile.getActiveRulesByRepository("fb-contrib").isEmpty();}private boolean hasActiveFindSecBugsRules(){return !this.profile.getActiveRulesByRepository("findsecbugs").isEmpty();}private boolean hasActiveFindSecBugsJspRules(){return !this.profile.getActiveRulesByRepository("findsecbugs-jsp").isEmpty();}public void execute(SensorContext context){if ((!hasActiveFindbugsRules()) && (!hasActiveFbContribRules()) && (!hasActiveFindSecBugsRules()) && (!hasActiveFindSecBugsJspRules())) {return;}Collection<ReportedBug> collection = this.executor.execute(hasActiveFbContribRules(), (hasActiveFindSecBugsRules()) || (hasActiveFindSecBugsJspRules()));for (ReportedBug bugInstance : collection) {try{String[] repos = { "findbugs", "fb-contrib", "findsecbugs", "findsecbugs-jsp" };ActiveRule rule = null;for (String repoKey : repos){rule = this.ruleFinder.findByInternalKey(repoKey, bugInstance.getType());if (rule != null) {break;}}if (rule == null){LOG.warn("Findbugs rule '{}' is not active in Sonar.", bugInstance.getType());}else{String className = bugInstance.getClassName();String longMessage = bugInstance.getMessage();int line = bugInstance.getStartLine();InputFile resource = null;resource = this.byteCodeResourceLocator.findJavaClassFile(className, this.fs);if (resource != null){insertIssue(rule, resource, line, longMessage);}else{File classFile = findOriginalClassForBug(bugInstance.getClassName());resource = this.byteCodeResourceLocator.findJavaOuterClassFile(className, classFile, this.fs);if (resource != null) {insertIssue(rule, resource, line, longMessage);} else if (classFile != null) {try{SmapParser.SmapLocation location = this.byteCodeResourceLocator.extractSmapLocation(className, line, classFile);if (location != null){if (!location.isPrimaryFile) {continue;}resource = this.byteCodeResourceLocator.buildInputFile(location.fileInfo.path, this.fs);if (resource != null) {insertIssue(rule, resource, location.line, longMessage);}}else{resource = this.byteCodeResourceLocator.findTemplateFile(className, this.fs);if (resource != null){insertIssue(rule, resource, line, longMessage);continue;}}}catch (ClassMetadataLoadingException e){LOG.warn("Failed to load the class file metadata", e);}} else {LOG.warn("The class '" + className + "' could not be matched to its original source file. It might be a dynamically generated class.");}}}}catch (Exception e){String bugInstanceDebug = String.format("[BugInstance type=%s, class=%s, line=%s]", new Object[] { bugInstance.getType(), bugInstance.getClassName(), Integer.valueOf(bugInstance.getStartLine()) });LOG.warn("An error occurs while processing the bug instance " + bugInstanceDebug, e);}}}protected void insertIssue(ActiveRule rule, InputFile resource, int line, String message){NewIssue newIssue = this.sensorContext.newIssue().forRule(rule.ruleKey());NewIssueLocation location = newIssue.newLocation().on(resource).at(resource.selectLine(line > 0 ? line : 1)).message(message);newIssue.at(location);newIssue.save();}private File findOriginalClassForBug(String className){String classFile = className.replaceAll("\\.", "/").concat(".class");for (File classPath : this.javaResourceLocator.classpath()) {if (classPath.isDirectory()){File testClassFile = new File(classPath, classFile);if (testClassFile.exists()) {return testClassFile;}}}return null;}public void describe(SensorDescriptor descriptor){descriptor.onlyOnLanguages(new String[] { "java", "jsp" });descriptor.name("FindBugs Sensor");} }

FindbugsConfiguration類,這個(gè)類中定義了findbugs plugin相關(guān)工作空間,排除java文件,掃描生成文件等等。

public class FindbugsConfiguration {private static final Logger LOG = LoggerFactory.getLogger(FindbugsExecutor.class);private final FileSystem fileSystem;private final Settings settings;private final RulesProfile profile;private final FindbugsProfileExporter exporter;private final JavaResourceLocator javaResourceLocator;private File jsr305Lib;private File annotationsLib;private File fbContrib;private File findSecBugs;public FindbugsConfiguration(FileSystem fileSystem, Settings settings, RulesProfile profile, FindbugsProfileExporter exporter, JavaResourceLocator javaResourceLocator){this.fileSystem = fileSystem;this.settings = settings;this.profile = profile;this.exporter = exporter;this.javaResourceLocator = javaResourceLocator;}public File getTargetXMLReport(){return new File(this.fileSystem.workDir(), "findbugs-result.xml");}public Project getFindbugsProject()throws IOException{Project findbugsProject = new Project();for (Iterator localIterator1 = getSourceFiles().iterator(); localIterator1.hasNext();){file = (File)localIterator1.next();if (FilenameUtils.getExtension(file.getName()).equals("java")) {findbugsProject.addFile(file.getCanonicalPath());}}File file;Object classFilesToAnalyze = new ArrayList(this.javaResourceLocator.classFilesToAnalyze());for (File file : this.javaResourceLocator.classpath()){if (file.isDirectory()) {((List)classFilesToAnalyze).addAll(scanForAdditionalClasses(file));}findbugsProject.addAuxClasspathEntry(file.getCanonicalPath());}boolean hasJspFiles = this.fileSystem.hasFiles(this.fileSystem.predicates().hasLanguage("jsp"));boolean hasPrecompiledJsp = false;for (File classToAnalyze : (List)classFilesToAnalyze){String absolutePath = classToAnalyze.getCanonicalPath();if ((hasJspFiles) && (!hasPrecompiledJsp) && ((absolutePath.endsWith("_jsp.class")) || (absolutePath.contains("/jsp_servlet/")))) {hasPrecompiledJsp = true;}findbugsProject.addFile(absolutePath);}if (((List)classFilesToAnalyze).isEmpty()){LOG.warn("Findbugs needs sources to be compiled. Please build project before executing sonar or check the location of compiled classes to make it possible for Findbugs to analyse your project.");if (hasSourceFiles()) {throw new IllegalStateException("This project contains Java source files that are not compiled.");}}if ((hasJspFiles) && (!hasPrecompiledJsp)) {LOG.warn("JSP files were found in the current project but FindBugs requires their precompiled form. For more information on how to configure JSP precompilation : https://github.com/find-sec-bugs/find-sec-bugs/wiki/JSP-precompilation");}copyLibs();if (this.annotationsLib != null){findbugsProject.addAuxClasspathEntry(this.annotationsLib.getCanonicalPath());findbugsProject.addAuxClasspathEntry(this.jsr305Lib.getCanonicalPath());}findbugsProject.setCurrentWorkingDirectory(this.fileSystem.workDir());return findbugsProject;}private Iterable<File> getSourceFiles(){FilePredicates pred = this.fileSystem.predicates();return this.fileSystem.files(pred.and(new FilePredicate[] {pred.hasType(InputFile.Type.MAIN), pred.hasLanguage("java"), pred.not(pred.matchesPathPattern("**/package-info.java")) }));}private boolean hasSourceFiles(){FilePredicates pred = this.fileSystem.predicates();return this.fileSystem.hasFiles(pred.and(new FilePredicate[] {pred.hasType(InputFile.Type.MAIN), pred.hasLanguage("java"), pred.not(pred.matchesPathPattern("**/package-info.java")) }));}@VisibleForTestingFile saveIncludeConfigXml()throws IOException{StringWriter conf = new StringWriter();this.exporter.exportProfile(this.profile, conf);File file = new File(this.fileSystem.workDir(), "findbugs-include.xml");FileUtils.write(file, conf.toString(), "UTF-8");return file;}public static List<File> scanForAdditionalClasses(File folder)throws IOException{List<File> allFiles = new ArrayList();Queue<File> dirs = new LinkedList();dirs.add(folder);while (!dirs.isEmpty()){File dirPoll = (File)dirs.poll();if (dirPoll == null) {break;}for (File f : dirPoll.listFiles()) {if (f.isDirectory()) {dirs.add(f);} else if ((f.isFile()) && (f.getName().endsWith(".class"))) {allFiles.add(f);}}}return allFiles;}@VisibleForTestingList<File> getExcludesFilters(){List<File> result = Lists.newArrayList();PathResolver pathResolver = new PathResolver();String[] filters = this.settings.getStringArray("sonar.findbugs.excludesFilters");for (String excludesFilterPath : filters){excludesFilterPath = StringUtils.trim(excludesFilterPath);if (StringUtils.isNotBlank(excludesFilterPath)) {result.add(pathResolver.relativeFile(this.fileSystem.baseDir(), excludesFilterPath));}}return result;}public String getEffort(){return StringUtils.lowerCase(this.settings.getString("sonar.findbugs.effort"));}public String getConfidenceLevel(){return StringUtils.lowerCase(this.settings.getString("sonar.findbugs.confidenceLevel"));}public long getTimeout(){return this.settings.getLong("sonar.findbugs.timeout");}public void copyLibs(){if (this.jsr305Lib == null) {this.jsr305Lib = copyLib("/jsr305.jar");}if (this.annotationsLib == null) {this.annotationsLib = copyLib("/annotations.jar");}if (this.fbContrib == null) {this.fbContrib = copyLib("/fb-contrib.jar");}if (this.findSecBugs == null) {this.findSecBugs = copyLib("/findsecbugs-plugin.jar");}}public void stop(){if (this.jsr305Lib != null) {this.jsr305Lib.delete();}if (this.annotationsLib != null) {this.annotationsLib.delete();}if (this.fbContrib != null) {this.fbContrib.delete();}if (this.findSecBugs != null) {this.findSecBugs.delete();}}private File copyLib(String name){InputStream input = null;try{input = getClass().getResourceAsStream(name);File dir = new File(this.fileSystem.workDir(), "findbugs");FileUtils.forceMkdir(dir);File target = new File(dir, name);FileUtils.copyInputStreamToFile(input, target);return target;}catch (IOException e){throw new IllegalStateException("Fail to extract Findbugs dependency", e);}finally{IOUtils.closeQuietly(input);}}public File getFbContribJar(){return this.fbContrib;}public File getFindSecBugsJar(){return this.findSecBugs;}public static List<PropertyDefinition> getPropertyDefinitions(){String subCategory = "FindBugs";return ImmutableList.of(PropertyDefinition.builder("sonar.findbugs.effort").defaultValue("Default").category("java").subCategory(subCategory).name("Effort").description("Effort of the bug finders. Valid values are Min, Default and Max. Setting 'Max' increases precision but also increases memory consumption.").onQualifiers("TRK", new String[] { "BRC" }).build(), PropertyDefinition.builder("sonar.findbugs.timeout").defaultValue(Long.toString(600000L)).category("java").subCategory(subCategory).name("Timeout").description("Specifies the amount of time, in milliseconds, that FindBugs may run before it is assumed to be hung and is terminated. The default is 600,000 milliseconds, which is ten minutes.").onQualifiers("TRK", new String[] { "BRC" }).type(PropertyType.INTEGER).build(), PropertyDefinition.builder("sonar.findbugs.excludesFilters").category("java").subCategory(subCategory).name("Excludes Filters").description("Paths to findbugs filter-files with exclusions.").onQualifiers("TRK", new String[] { "BRC" }).multiValues(true).build(), PropertyDefinition.builder("sonar.findbugs.confidenceLevel").defaultValue("medium").category("java").subCategory(subCategory).name("Confidence Level").description("Specifies the confidence threshold (previously called \"priority\") for reporting issues. If set to \"low\", confidence is not used to filter bugs. If set to \"medium\" (the default), low confidence issues are supressed. If set to \"high\", only high confidence bugs are reported. ").onQualifiers("TRK", new String[] { "BRC" }).build());} }

FindbugsExecutor 類這個(gè)類定義了該plugin 有執(zhí)行掃描功能,去創(chuàng)建線程執(zhí)行,在執(zhí)行之前去加載其他插件。其他plugin可能只提供規(guī)則,但是這個(gè)plugin可以具備掃描執(zhí)行能力。

@BatchSide public class FindbugsExecutor {private static final String FINDBUGS_CORE_PLUGIN_ID = "edu.umd.cs.findbugs.plugins.core";private static final Logger LOG = LoggerFactory.getLogger(FindbugsExecutor.class);private static Map<String, Integer> priorityNameToValueMap = new HashMap();static{priorityNameToValueMap.put("high", Integer.valueOf(1));priorityNameToValueMap.put("medium", Integer.valueOf(2));priorityNameToValueMap.put("low", Integer.valueOf(3));priorityNameToValueMap.put("experimental", Integer.valueOf(4));}private static final Integer DEFAULT_PRIORITY = Integer.valueOf(2);private final FindbugsConfiguration configuration;public FindbugsExecutor(FindbugsConfiguration configuration){this.configuration = configuration;}@VisibleForTestingCollection<ReportedBug> execute(){return execute(true);}public Collection<ReportedBug> execute(boolean useAllPlugin){return execute(useAllPlugin, useAllPlugin);}public Collection<ReportedBug> execute(boolean useFbContrib, boolean useFindSecBugs){SecurityManager currentSecurityManager = System.getSecurityManager();ClassLoader initialClassLoader = Thread.currentThread().getContextClassLoader();Thread.currentThread().setContextClassLoader(FindBugs2.class.getClassLoader());Locale initialLocale = Locale.getDefault();Locale.setDefault(Locale.ENGLISH);OutputStream xmlOutput = null;Collection<Plugin> customPlugins = null;ExecutorService executorService = Executors.newSingleThreadExecutor();try{FindBugs2 engine = new FindBugs2();Project project = this.configuration.getFindbugsProject();if (project.getFileCount() == 0){LOG.info("Findbugs analysis skipped for this project.");return new ArrayList();}customPlugins = loadFindbugsPlugins(useFbContrib, useFindSecBugs);disableUpdateChecksOnEveryPlugin();engine.setProject(project);XMLBugReporter xmlBugReporter = new XMLBugReporter(project);xmlBugReporter.setPriorityThreshold(determinePriorityThreshold().intValue());xmlBugReporter.setAddMessages(true);File xmlReport = this.configuration.getTargetXMLReport();LOG.info("Findbugs output report: " + xmlReport.getAbsolutePath());xmlOutput = FileUtils.openOutputStream(xmlReport);xmlBugReporter.setOutputStream(new PrintStream(xmlOutput));engine.setBugReporter(xmlBugReporter);UserPreferences userPreferences = UserPreferences.createDefaultUserPreferences();userPreferences.setEffort(this.configuration.getEffort());engine.setUserPreferences(userPreferences);engine.addFilter(this.configuration.saveIncludeConfigXml().getAbsolutePath(), true);for (Object localObject1 = this.configuration.getExcludesFilters().iterator(); ((Iterator)localObject1).hasNext();){File filterFile = (File)((Iterator)localObject1).next();if (filterFile.isFile()){LOG.info("Use filter-file: {}", filterFile);engine.addFilter(filterFile.getAbsolutePath(), false);}else{LOG.warn("FindBugs filter-file not found: {}", filterFile);}}engine.setDetectorFactoryCollection(DetectorFactoryCollection.instance());engine.setAnalysisFeatureSettings(FindBugs.DEFAULT_EFFORT);engine.finishSettings();executorService.submit(new FindbugsTask(engine)).get(this.configuration.getTimeout(), TimeUnit.MILLISECONDS);return toReportedBugs(xmlBugReporter.getBugCollection());}catch (TimeoutException e){throw new IllegalStateException("Can not execute Findbugs with a timeout threshold value of " + this.configuration.getTimeout() + " milliseconds", e);}catch (Exception e){throw new IllegalStateException("Can not execute Findbugs", e);}finally{System.setSecurityManager(currentSecurityManager);resetCustomPluginList(customPlugins);executorService.shutdown();IOUtils.closeQuietly(xmlOutput);Thread.currentThread().setContextClassLoader(initialClassLoader);Locale.setDefault(initialLocale);}}private static Collection<ReportedBug> toReportedBugs(BugCollection bugCollection){Collection<ReportedBug> bugs = new ArrayList();for (BugInstance bugInstance : bugCollection) {if (bugInstance.getPrimarySourceLineAnnotation() == null) {LOG.warn("No source line for " + bugInstance.getType());} else {bugs.add(new ReportedBug(bugInstance));}}return bugs;}private Integer determinePriorityThreshold(){Integer integer = (Integer)priorityNameToValueMap.get(this.configuration.getConfidenceLevel());if (integer == null) {integer = DEFAULT_PRIORITY;}return integer;}private static class FindbugsTaskimplements Callable<Object>{private final FindBugs2 engine;public FindbugsTask(FindBugs2 engine){this.engine = engine;}public Object call(){try{this.engine.execute();return null;}catch (InterruptedException|IOException e){throw Throwables.propagate(e);}finally{this.engine.dispose();}}}private Collection<Plugin> loadFindbugsPlugins(boolean useFbContrib, boolean useFindSecBugs){ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();List<String> pluginJarPathList = Lists.newArrayList();URL url;try{Enumeration<URL> urls = contextClassLoader.getResources("findbugs.xml");while (urls.hasMoreElements()){url = (URL)urls.nextElement();pluginJarPathList.add(normalizeUrl(url));}if ((useFbContrib) && (this.configuration.getFbContribJar() != null)) {pluginJarPathList.add(this.configuration.getFbContribJar().getAbsolutePath());}if ((useFindSecBugs) && (this.configuration.getFindSecBugsJar() != null)) {pluginJarPathList.add(this.configuration.getFindSecBugsJar().getAbsolutePath());}}catch (IOException e){throw new IllegalStateException(e);}catch (URISyntaxException e){throw new IllegalStateException(e);}List<Plugin> customPluginList = Lists.newArrayList();for (String path : pluginJarPathList) {try{Plugin plugin = Plugin.addCustomPlugin(new File(path).toURI(), contextClassLoader);if (plugin != null){customPluginList.add(plugin);LOG.info("Loading findbugs plugin: " + path);}}catch (PluginException e){LOG.warn("Failed to load plugin for custom detector: " + path);LOG.debug("Cause of failure", e);}catch (DuplicatePluginIdException e){if (!"edu.umd.cs.findbugs.plugins.core".equals(e.getPluginId())) {LOG.debug("Plugin already loaded: exception ignored: " + e.getMessage(), e);}}}return customPluginList;}private static String normalizeUrl(URL url)throws URISyntaxException{return StringUtils.removeStart(StringUtils.substringBefore(url.toURI().getSchemeSpecificPart(), "!"), "file:");}private static void disableUpdateChecksOnEveryPlugin(){for (Plugin plugin : ) {plugin.setMyGlobalOption("noUpdateChecks", "true");}}private static void resetCustomPluginList(Collection<Plugin> customPlugins){if (customPlugins != null) {for (Plugin plugin : customPlugins) {Plugin.removeCustomPlugin(plugin);}}} }

findbugs-result.xml 掃描相關(guān)的類:

class FindbugsXmlReportParser {private final File findbugsXmlReport;private final String findbugsXmlReportPath;public FindbugsXmlReportParser(File findbugsXmlReport){this.findbugsXmlReport = findbugsXmlReport;this.findbugsXmlReportPath = findbugsXmlReport.getAbsolutePath();if (!findbugsXmlReport.exists()) {throw new IllegalStateException("The findbugs XML report can't be found at '" + this.findbugsXmlReportPath + "'");}}public List<XmlBugInstance> getBugInstances(){List<XmlBugInstance> result = Lists.newArrayList();try{SMInputFactory inf = new SMInputFactory(XMLInputFactory.newInstance());SMInputCursor cursor = inf.rootElementCursor(this.findbugsXmlReport).advance();SMInputCursor bugInstanceCursor = cursor.childElementCursor("BugInstance").advance();while (bugInstanceCursor.asEvent() != null){XmlBugInstance xmlBugInstance = new XmlBugInstance();xmlBugInstance.type = bugInstanceCursor.getAttrValue("type");xmlBugInstance.longMessage = "";result.add(xmlBugInstance);ImmutableList.Builder<XmlSourceLineAnnotation> lines = ImmutableList.builder();SMInputCursor bugInstanceChildCursor = bugInstanceCursor.childElementCursor().advance();while (bugInstanceChildCursor.asEvent() != null){String nodeName = bugInstanceChildCursor.getLocalName();if ("LongMessage".equals(nodeName)){xmlBugInstance.longMessage = bugInstanceChildCursor.collectDescendantText();}else if ("SourceLine".equals(nodeName)){XmlSourceLineAnnotation xmlSourceLineAnnotation = new XmlSourceLineAnnotation();xmlSourceLineAnnotation.parseStart(bugInstanceChildCursor.getAttrValue("start"));xmlSourceLineAnnotation.parseEnd(bugInstanceChildCursor.getAttrValue("end"));xmlSourceLineAnnotation.parsePrimary(bugInstanceChildCursor.getAttrValue("primary"));xmlSourceLineAnnotation.className = bugInstanceChildCursor.getAttrValue("classname");lines.add(xmlSourceLineAnnotation);}bugInstanceChildCursor.advance();}xmlBugInstance.sourceLines = lines.build();bugInstanceCursor.advance();}cursor.getStreamReader().closeCompletely();}catch (XMLStreamException e){throw new IllegalStateException("Unable to parse the Findbugs XML Report '" + this.findbugsXmlReportPath + "'", e);}return result;}public static class XmlBugInstance{private String type;private String longMessage;private List<FindbugsXmlReportParser.XmlSourceLineAnnotation> sourceLines;public String getType(){return this.type;}public String getLongMessage(){return this.longMessage;}@CheckForNullpublic FindbugsXmlReportParser.XmlSourceLineAnnotation getPrimarySourceLine(){for (FindbugsXmlReportParser.XmlSourceLineAnnotation sourceLine : this.sourceLines) {if (sourceLine.isPrimary()) {return sourceLine;}}return this.sourceLines.isEmpty() ? null : (FindbugsXmlReportParser.XmlSourceLineAnnotation)this.sourceLines.get(0);}}public static class XmlSourceLineAnnotation{private boolean primary;private Integer start;private Integer end;@VisibleForTestingprotected String className;public void parseStart(String attrValue){try{this.start = Integer.valueOf(Integer.parseInt(attrValue));}catch (NumberFormatException e){this.start = null;}}public void parseEnd(String attrValue){try{this.end = Integer.valueOf(Integer.parseInt(attrValue));}catch (NumberFormatException e){this.end = null;}}public void parsePrimary(String attrValue){this.primary = Boolean.parseBoolean(attrValue);}public boolean isPrimary(){return this.primary;}public Integer getStart(){return this.start;}public Integer getEnd(){return this.end;}public String getClassName(){return this.className;}public String getSonarJavaFileKey(){if (this.className.indexOf('$') > -1) {return this.className.substring(0, this.className.indexOf('$'));}return this.className;}} }




總結(jié)

以上是生活随笔為你收集整理的sonar findbugs plugin源码研究的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。