001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2009 SonarSource SA
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.utils.AnnotationUtils;
027    import org.sonar.check.Check;
028    
029    import java.lang.reflect.Field;
030    import java.util.Collection;
031    import java.util.List;
032    
033    /**
034     * @since 2.3
035     */
036    public final class AnnotationRuleRepository extends RuleRepository {
037    
038      private static final Logger LOG = LoggerFactory.getLogger(AnnotationRuleRepository.class);
039    
040      private Collection<Class> annotatedClasses;
041    
042      /**
043       * Use the factory method create()
044       */
045      private AnnotationRuleRepository(String key, String language, String name, Collection<Class> annotatedClasses) {
046        super(key, language);
047        setName(name);
048        this.annotatedClasses = annotatedClasses;
049      }
050    
051      public static AnnotationRuleRepository create(String key, String language, String name, Collection<Class> annotatedClasses) {
052        return new AnnotationRuleRepository(key, language, name, annotatedClasses);
053      }
054    
055      @Override
056      public List<Rule> createRules() {
057        List<Rule> rules = Lists.newArrayList();
058        for (Class annotatedClass : annotatedClasses) {
059          rules.add(create(annotatedClass));
060        }
061        return rules;
062      }
063    
064      private Rule create(Class annotatedClass) {
065        org.sonar.check.Rule ruleAnnotation = AnnotationUtils.getClassAnnotation(annotatedClass, org.sonar.check.Rule.class);
066        if (ruleAnnotation != null) {
067          return toRule(annotatedClass, ruleAnnotation);
068        }
069        Check checkAnnotation = AnnotationUtils.getClassAnnotation(annotatedClass, Check.class);
070        if (checkAnnotation != null) {
071          return toRule(annotatedClass, checkAnnotation);
072        }
073        LOG.warn("The class " + annotatedClass.getCanonicalName() + " is not a check template. It should be annotated with " + Rule.class);
074        return null;
075      }
076    
077      private Rule toRule(Class clazz, org.sonar.check.Rule ruleAnnotation) {
078        String key = StringUtils.defaultIfEmpty(ruleAnnotation.key(), clazz.getCanonicalName());
079        Rule rule = Rule.create(getKey(), key, ruleAnnotation.name());
080        rule.setDescription(ruleAnnotation.description());
081        rule.setRulesCategory(RulesCategory.fromIsoCategory(ruleAnnotation.isoCategory()));
082        rule.setPriority(RulePriority.fromCheckPriority(ruleAnnotation.priority()));
083    
084        Field[] fields = clazz.getDeclaredFields();
085        if (fields != null) {
086          for (Field field : fields) {
087            addRuleProperty(rule, field);
088          }
089        }
090    
091        return rule;
092      }
093    
094      private Rule toRule(Class clazz, Check checkAnnotation) {
095        String key = StringUtils.defaultIfEmpty(checkAnnotation.key(), clazz.getCanonicalName());
096        Rule rule = Rule.create(getKey(), key, checkAnnotation.title());
097        rule.setDescription(checkAnnotation.description());
098        rule.setRulesCategory(RulesCategory.fromIsoCategory(checkAnnotation.isoCategory()));
099        rule.setPriority(RulePriority.fromCheckPriority(checkAnnotation.priority()));
100    
101        Field[] fields = clazz.getDeclaredFields();
102        if (fields != null) {
103          for (Field field : fields) {
104            addCheckProperty(rule, field);
105          }
106        }
107        return rule;
108      }
109    
110      private void addRuleProperty(Rule rule, Field field) {
111        org.sonar.check.RuleProperty propertyAnnotation = field.getAnnotation(org.sonar.check.RuleProperty.class);
112        if (propertyAnnotation != null) {
113          String fieldKey = StringUtils.defaultIfEmpty(propertyAnnotation.key(), field.getName());
114          RuleParam param = rule.createParameter(fieldKey);
115          param.setDescription(propertyAnnotation.description());
116          param.setDefaultValue(propertyAnnotation.defaultValue());
117        }
118      }
119    
120      private void addCheckProperty(Rule rule, Field field) {
121        org.sonar.check.CheckProperty propertyAnnotation = field.getAnnotation(org.sonar.check.CheckProperty.class);
122        if (propertyAnnotation != null) {
123          String fieldKey = StringUtils.defaultIfEmpty(propertyAnnotation.key(), field.getName());
124          RuleParam param = rule.createParameter(fieldKey);
125          param.setDescription(propertyAnnotation.description());
126        }
127      }
128    }