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 org.apache.commons.lang.StringUtils;
024import org.sonar.api.batch.rule.Checks;
025import org.sonar.api.profiles.RulesProfile;
026import org.sonar.api.rules.ActiveRule;
027import org.sonar.api.rules.ActiveRuleParam;
028import org.sonar.api.utils.AnnotationUtils;
029import org.sonar.api.utils.FieldUtils2;
030import org.sonar.api.utils.SonarException;
031import org.sonar.check.Rule;
032import org.sonar.check.RuleProperty;
033
034import java.lang.reflect.Field;
035import java.util.Collection;
036import java.util.List;
037import java.util.Map;
038
039/**
040 * @since 2.3
041 * @deprecated since 4.2 use {@link Checks}
042 */
043@Deprecated
044public 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  public 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}