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