001    /*
002     * SonarQube, open source software quality management tool.
003     * Copyright (C) 2008-2014 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * SonarQube 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     * SonarQube 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 License
017     * along with this program; if not, write to the Free Software Foundation,
018     * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019     */
020    package org.sonar.api.checks;
021    
022    import com.google.common.collect.Maps;
023    import org.apache.commons.lang.StringUtils;
024    import org.sonar.api.batch.rule.Checks;
025    import org.sonar.api.profiles.RulesProfile;
026    import org.sonar.api.rules.ActiveRule;
027    import org.sonar.api.rules.ActiveRuleParam;
028    import org.sonar.api.utils.AnnotationUtils;
029    import org.sonar.api.utils.FieldUtils2;
030    import org.sonar.api.utils.SonarException;
031    import org.sonar.check.Rule;
032    import org.sonar.check.RuleProperty;
033    
034    import java.lang.reflect.Field;
035    import java.util.Collection;
036    import java.util.List;
037    import java.util.Map;
038    
039    /**
040     * @since 2.3
041     * @deprecated since 4.2 use {@link Checks}
042     */
043    @Deprecated
044    public final class AnnotationCheckFactory extends CheckFactory {
045    
046      private static final String CAN_NOT_INSTANTIATE_THE_CHECK_RELATED_TO_THE_RULE = "Can not instantiate the check related to the rule ";
047      private Map<String, Object> checksByKey = Maps.newHashMap();
048    
049      private AnnotationCheckFactory(RulesProfile profile, String repositoryKey, Collection checks) {
050        super(profile, repositoryKey);
051        groupByKey(checks);
052      }
053    
054      public static AnnotationCheckFactory create(RulesProfile profile, String repositoryKey, Collection checkClasses) {
055        AnnotationCheckFactory factory = new AnnotationCheckFactory(profile, repositoryKey, checkClasses);
056        factory.init();
057        return factory;
058      }
059    
060      private void groupByKey(Collection checks) {
061        for (Object check : checks) {
062          String key = getRuleKey(check);
063          if (key != null) {
064            checksByKey.put(key, check);
065          }
066        }
067      }
068    
069      @Override
070      protected Object createCheck(ActiveRule activeRule) {
071        Object object = checksByKey.get(activeRule.getConfigKey());
072        if (object != null) {
073          return instantiate(activeRule, object);
074        }
075        return null;
076      }
077    
078      private Object instantiate(ActiveRule activeRule, Object checkClassOrInstance) {
079        try {
080          Object check = checkClassOrInstance;
081          if (check instanceof Class) {
082            check = ((Class) checkClassOrInstance).newInstance();
083          }
084          configureFields(activeRule, check);
085          return check;
086    
087        } catch (InstantiationException e) {
088          throw new SonarException(CAN_NOT_INSTANTIATE_THE_CHECK_RELATED_TO_THE_RULE + activeRule, e);
089    
090        } catch (IllegalAccessException e) {
091          throw new SonarException(CAN_NOT_INSTANTIATE_THE_CHECK_RELATED_TO_THE_RULE + activeRule, e);
092        }
093      }
094    
095      private void configureFields(ActiveRule activeRule, Object check) {
096        for (ActiveRuleParam param : activeRule.getActiveRuleParams()) {
097          Field field = getField(check, param.getKey());
098          if (field == null) {
099            throw new SonarException("The field " + param.getKey() + " does not exist or is not annotated with @RuleProperty in the class " + check.getClass().getName());
100          }
101          if (StringUtils.isNotBlank(param.getValue())) {
102            configureField(check, field, param.getValue());
103          }
104        }
105    
106      }
107    
108      private void configureField(Object check, Field field, String value) {
109        try {
110          field.setAccessible(true);
111    
112          if (field.getType().equals(String.class)) {
113            field.set(check, value);
114    
115          } else if ("int".equals(field.getType().getSimpleName())) {
116            field.setInt(check, Integer.parseInt(value));
117    
118          } else if ("short".equals(field.getType().getSimpleName())) {
119            field.setShort(check, Short.parseShort(value));
120    
121          } else if ("long".equals(field.getType().getSimpleName())) {
122            field.setLong(check, Long.parseLong(value));
123    
124          } else if ("double".equals(field.getType().getSimpleName())) {
125            field.setDouble(check, Double.parseDouble(value));
126    
127          } else if ("boolean".equals(field.getType().getSimpleName())) {
128            field.setBoolean(check, Boolean.parseBoolean(value));
129    
130          } else if ("byte".equals(field.getType().getSimpleName())) {
131            field.setByte(check, Byte.parseByte(value));
132    
133          } else if (field.getType().equals(Integer.class)) {
134            field.set(check, Integer.parseInt(value));
135    
136          } else if (field.getType().equals(Long.class)) {
137            field.set(check, Long.parseLong(value));
138    
139          } else if (field.getType().equals(Double.class)) {
140            field.set(check, Double.parseDouble(value));
141    
142          } else if (field.getType().equals(Boolean.class)) {
143            field.set(check, Boolean.parseBoolean(value));
144    
145          } else {
146            throw new SonarException("The type of the field " + field + " is not supported: " + field.getType());
147          }
148        } catch (IllegalAccessException e) {
149          throw new SonarException("Can not set the value of the field " + field + " in the class: " + check.getClass().getName(), e);
150        }
151      }
152    
153      private Field getField(Object check, String key) {
154        List<Field> fields = FieldUtils2.getFields(check.getClass(), true);
155        for (Field field : fields) {
156          RuleProperty propertyAnnotation = field.getAnnotation(RuleProperty.class);
157          if (propertyAnnotation != null && (StringUtils.equals(key, field.getName()) || StringUtils.equals(key, propertyAnnotation.key()))) {
158            return field;
159          }
160        }
161        return null;
162      }
163    
164      private String getRuleKey(Object annotatedClassOrObject) {
165        String key = null;
166        Rule ruleAnnotation = AnnotationUtils.getAnnotation(annotatedClassOrObject, Rule.class);
167        if (ruleAnnotation != null) {
168          key = ruleAnnotation.key();
169        }
170        Class clazz = annotatedClassOrObject.getClass();
171        if (annotatedClassOrObject instanceof Class) {
172          clazz = (Class) annotatedClassOrObject;
173        }
174        return StringUtils.defaultIfEmpty(key, clazz.getCanonicalName());
175      }
176    }