001/*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 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 */
020package org.sonar.plugins.findbugs.xml;
021
022import com.thoughtworks.xstream.XStream;
023import com.thoughtworks.xstream.annotations.XStreamAlias;
024import com.thoughtworks.xstream.annotations.XStreamImplicit;
025import org.apache.commons.lang.StringUtils;
026import org.sonar.api.rules.RulePriority;
027import org.sonar.plugins.findbugs.FindbugsLevelUtils;
028
029import java.util.*;
030
031@XStreamAlias("FindBugsFilter")
032public class FindBugsFilter {
033
034  private static final String PATTERN_SEPARATOR = ",";
035  private static final String CODE_SEPARATOR = ",";
036  private static final String CATEGORY_SEPARATOR = ",";
037
038  @XStreamImplicit
039  private List<Match> matchs;
040
041  public FindBugsFilter() {
042    matchs = new ArrayList<Match>();
043  }
044
045  public String toXml() {
046    XStream xstream = createXStream();
047    return xstream.toXML(this);
048  }
049
050  public List<Match> getMatchs() {
051    return matchs;
052  }
053
054  public List<Match> getChildren() {
055    return matchs;
056  }
057
058  public void setMatchs(List<Match> matchs) {
059    this.matchs = matchs;
060  }
061
062  public void addMatch(Match child) {
063    matchs.add(child);
064  }
065
066  public Map<String, RulePriority> getPatternLevels(FindbugsLevelUtils priorityMapper) {
067    BugInfoSplitter splitter = new BugInfoSplitter() {
068      public String getSeparator() {
069        return PATTERN_SEPARATOR;
070      }
071
072      public String getVar(Bug bug) {
073        return bug.getPattern();
074      }
075    };
076    return processMatches(priorityMapper, splitter);
077  }
078
079  public Map<String, RulePriority> getCodeLevels(FindbugsLevelUtils priorityMapper) {
080    BugInfoSplitter splitter = new BugInfoSplitter() {
081      public String getSeparator() {
082        return CODE_SEPARATOR;
083      }
084
085      public String getVar(Bug bug) {
086        return bug.getCode();
087      }
088    };
089    return processMatches(priorityMapper, splitter);
090  }
091
092  public Map<String, RulePriority> getCategoryLevels(FindbugsLevelUtils priorityMapper) {
093    BugInfoSplitter splitter = new BugInfoSplitter() {
094      public String getSeparator() {
095        return CATEGORY_SEPARATOR;
096      }
097
098      public String getVar(Bug bug) {
099        return bug.getCategory();
100      }
101    };
102    return processMatches(priorityMapper, splitter);
103  }
104
105  private RulePriority getRulePriority(Priority priority, FindbugsLevelUtils priorityMapper) {
106    return priority != null ? priorityMapper.from(priority.getValue()) : null;
107  }
108
109  private Map<String, RulePriority> processMatches(FindbugsLevelUtils priorityMapper, BugInfoSplitter splitter) {
110    Map<String, RulePriority> result = new HashMap<String, RulePriority>();
111    for (Match child : getChildren()) {
112      if (child.getOrs() != null) {
113        for (OrFilter orFilter : child.getOrs()) {
114          completeLevels(result, orFilter.getBugs(), child.getPriority(), priorityMapper, splitter);
115        }
116      }
117      if (child.getBug() != null) {
118        completeLevels(result, Arrays.asList(child.getBug()), child.getPriority(), priorityMapper, splitter);
119      }
120    }
121    return result;
122  }
123
124  private void completeLevels(Map<String, RulePriority> result, List<Bug> bugs, Priority priority, FindbugsLevelUtils priorityMapper, BugInfoSplitter splitter) {
125    if (bugs == null) {
126      return;
127    }
128    RulePriority rulePriority = getRulePriority(priority, priorityMapper);
129    for (Bug bug : bugs) {
130      String varToSplit = splitter.getVar(bug);
131      if (!StringUtils.isBlank(varToSplit)) {
132        String[] splitted = StringUtils.split(varToSplit, splitter.getSeparator());
133        for (String code : splitted) {
134          mapRulePriority(result, rulePriority, code);
135        }
136      }
137    }
138  }
139
140  private interface BugInfoSplitter {
141    String getVar(Bug bug);
142
143    String getSeparator();
144  }
145
146  private void mapRulePriority(Map<String, RulePriority> prioritiesByRule, RulePriority priority, String key) {
147    if (prioritiesByRule.containsKey(key) && prioritiesByRule.get(key) != null) {
148      if (prioritiesByRule.get(key).compareTo(priority) < 0) {
149        prioritiesByRule.put(key, priority);
150      }
151    } else {
152      prioritiesByRule.put(key, priority);
153    }
154  }
155
156  public static XStream createXStream() {
157    XStream xstream = new XStream();
158    xstream.setClassLoader(FindBugsFilter.class.getClassLoader());
159    xstream.processAnnotations(FindBugsFilter.class);
160    xstream.processAnnotations(Match.class);
161    xstream.processAnnotations(Bug.class);
162    xstream.processAnnotations(Priority.class);
163    xstream.processAnnotations(ClassFilter.class);
164    xstream.processAnnotations(PackageFilter.class);
165    xstream.processAnnotations(MethodFilter.class);
166    xstream.processAnnotations(FieldFilter.class);
167    xstream.processAnnotations(LocalFilter.class);
168    xstream.processAnnotations(OrFilter.class);
169    return xstream;
170  }
171}