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