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     */
020    package org.sonar.api.rules;
021    
022    import com.google.common.collect.Lists;
023    import org.apache.commons.lang.StringUtils;
024    import org.slf4j.Logger;
025    import org.slf4j.LoggerFactory;
026    import org.sonar.api.ServerComponent;
027    import org.sonar.api.utils.AnnotationUtils;
028    import org.sonar.check.Check;
029    
030    import java.lang.reflect.Field;
031    import java.util.Collection;
032    import java.util.List;
033    
034    /**
035     * @since 2.3
036     */
037    public final class AnnotationRuleParser implements ServerComponent {
038    
039      private static final Logger LOG = LoggerFactory.getLogger(AnnotationRuleParser.class);
040    
041      public List<Rule> parse(String repositoryKey, Collection<Class> annotatedClasses) {
042        List<Rule> rules = Lists.newArrayList();
043        for (Class annotatedClass : annotatedClasses) {
044          rules.add(create(repositoryKey, annotatedClass));
045        }
046        return rules;
047      }
048    
049      private Rule create(String repositoryKey, Class annotatedClass) {
050        org.sonar.check.Rule ruleAnnotation = AnnotationUtils.getClassAnnotation(annotatedClass, org.sonar.check.Rule.class);
051        if (ruleAnnotation != null) {
052          return toRule(repositoryKey, annotatedClass, ruleAnnotation);
053        }
054        Check checkAnnotation = AnnotationUtils.getClassAnnotation(annotatedClass, Check.class);
055        if (checkAnnotation != null) {
056          return toRule(repositoryKey, annotatedClass, checkAnnotation);
057        }
058        LOG.warn("The class " + annotatedClass.getCanonicalName() + " should be annotated with " + Rule.class);
059        return null;
060      }
061    
062      private Rule toRule(String repositoryKey, Class clazz, org.sonar.check.Rule ruleAnnotation) {
063        String ruleKey = StringUtils.defaultIfEmpty(ruleAnnotation.key(), clazz.getCanonicalName());
064        String ruleName = StringUtils.defaultIfEmpty(ruleAnnotation.name(), ruleKey);
065        Rule rule = Rule.create(repositoryKey, ruleKey, ruleName);
066        rule.setDescription(ruleAnnotation.description());
067        rule.setSeverity(RulePriority.fromCheckPriority(ruleAnnotation.priority()));
068        rule.setCardinality(ruleAnnotation.cardinality());
069    
070        Field[] fields = clazz.getDeclaredFields();
071        if (fields != null) {
072          for (Field field : fields) {
073            addRuleProperty(rule, field);
074          }
075        }
076    
077        return rule;
078      }
079    
080      private Rule toRule(String repositoryKey, Class clazz, Check checkAnnotation) {
081        String ruleKey = StringUtils.defaultIfEmpty(checkAnnotation.key(), clazz.getCanonicalName());
082        String ruleName = StringUtils.defaultIfEmpty(checkAnnotation.title(), ruleKey);
083        Rule rule = Rule.create(repositoryKey, ruleKey, ruleName);
084        rule.setDescription(checkAnnotation.description());
085        rule.setSeverity(RulePriority.fromCheckPriority(checkAnnotation.priority()));
086    
087        Field[] fields = clazz.getDeclaredFields();
088        if (fields != null) {
089          for (Field field : fields) {
090            addCheckProperty(rule, field);
091          }
092        }
093        return rule;
094      }
095    
096      private void addRuleProperty(Rule rule, Field field) {
097        org.sonar.check.RuleProperty propertyAnnotation = field.getAnnotation(org.sonar.check.RuleProperty.class);
098        if (propertyAnnotation != null) {
099          String fieldKey = StringUtils.defaultIfEmpty(propertyAnnotation.key(), field.getName());
100          RuleParam param = rule.createParameter(fieldKey);
101          param.setDescription(propertyAnnotation.description());
102          param.setDefaultValue(propertyAnnotation.defaultValue());
103        }
104      }
105    
106      private void addCheckProperty(Rule rule, Field field) {
107        org.sonar.check.CheckProperty propertyAnnotation = field.getAnnotation(org.sonar.check.CheckProperty.class);
108        if (propertyAnnotation != null) {
109          String fieldKey = StringUtils.defaultIfEmpty(propertyAnnotation.key(), field.getName());
110          RuleParam param = rule.createParameter(fieldKey);
111          param.setDescription(propertyAnnotation.description());
112        }
113      }
114    }