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