1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package de.smartics.properties.report;
17
18 import java.lang.reflect.Method;
19 import java.util.List;
20
21 import org.apache.commons.lang.ObjectUtils;
22
23 import com.thoughtworks.qdox.JavaProjectBuilder;
24 import com.thoughtworks.qdox.model.JavaAnnotation;
25 import com.thoughtworks.qdox.model.JavaClass;
26 import com.thoughtworks.qdox.model.JavaField;
27 import com.thoughtworks.qdox.model.JavaMethod;
28 import com.thoughtworks.qdox.model.expression.Expression;
29
30 import de.smartics.properties.api.core.annotations.PropertyMetaDataMethod;
31 import de.smartics.properties.api.core.domain.PropertyDescriptor;
32 import de.smartics.properties.report.data.PropertyReport;
33 import de.smartics.properties.report.data.PropertyReportItem;
34 import de.smartics.properties.report.data.PropertyReportSet;
35 import de.smartics.properties.report.data.ReportProblem;
36 import de.smartics.properties.report.data.SourceInfo;
37 import de.smartics.properties.report.data.ValueComment;
38 import de.smartics.properties.spi.core.metadata.PropertyMetaDataDefaults;
39 import de.smartics.properties.spi.core.metadata.PropertyMetaDataParser;
40 import de.smartics.properties.spi.core.metadata.projectdoc.ProjectdocAnnotationCollector;
41 import de.smartics.properties.spi.core.metadata.projectdoc.ProjectdocMetaData;
42 import de.smartics.properties.utils.RuntimeUtils;
43
44
45
46
47 class AddReportItemHelper
48 {
49
50
51
52
53
54
55
56 private static final Class<?>[] NO_PARAMS = new Class<?>[0];
57
58
59
60
61
62
63 private final RuntimeUtils runtimeUtils;
64
65
66
67
68 private final JavaProjectBuilder javaProjectBuilder;
69
70
71
72
73 private final JavaClass propertyDescriptorType;
74
75
76
77
78 private final Class<?> propertySetJavaClass;
79
80
81
82
83 private final ProjectdocAnnotationCollector projectdocCollector;
84
85
86
87
88
89 AddReportItemHelper(final RuntimeUtils runtimeUtils,
90 final JavaProjectBuilder javaProjectBuilder,
91 final JavaClass propertyDescriptorType) throws ClassNotFoundException
92 {
93 this.runtimeUtils = runtimeUtils;
94 this.javaProjectBuilder = javaProjectBuilder;
95 this.propertyDescriptorType = propertyDescriptorType;
96
97 this.propertySetJavaClass = runtimeUtils.loadClass(propertyDescriptorType);
98
99
100 final PropertyMetaDataDefaults defaults =
101 new PropertyMetaDataDefaults(propertySetJavaClass);
102 this.projectdocCollector =
103 new ProjectdocAnnotationCollector(propertySetJavaClass, defaults);
104 }
105
106
107
108
109
110
111
112
113
114
115
116 void addReportItems(final PropertyReport report)
117 {
118 addReportSet(report);
119 addReportPropertyItems(report);
120 }
121
122 private void addReportSet(final PropertyReport report)
123 {
124 final String type = propertyDescriptorType.getFullyQualifiedName();
125 final String comment = propertyDescriptorType.getComment();
126
127 final PropertyReportSet.Builder builder = new PropertyReportSet.Builder();
128 builder.withType(type);
129 builder.withComment(comment);
130
131 final PropertyMetaDataParser metaDataParser =
132 PropertyMetaDataParser.createWithoutContextAccess();
133 final String name =
134 metaDataParser.readPropertySetName(propertySetJavaClass);
135 builder.withPropertySetName(name);
136
137 final ProjectdocMetaData metaData = projectdocCollector.getParentMetadata();
138 builder.with(metaData);
139
140 final PropertyReportSet reportSet = builder.build();
141 report.handle(reportSet);
142 }
143
144 private void addReportPropertyItems(final PropertyReport report)
145 {
146 try
147 {
148 final Class<?> type = runtimeUtils.loadClass(propertyDescriptorType);
149 if (type == null)
150 {
151 return;
152 }
153
154 final List<JavaMethod> methods = propertyDescriptorType.getMethods(true);
155 for (final JavaMethod method : methods)
156 {
157 handleItem(report, type, method);
158 }
159 }
160 catch (final ClassNotFoundException e)
161 {
162 report.addProblem(new ReportProblem("Cannot load class '"
163 + propertyDescriptorType.getName()
164 + "'.", e));
165 }
166 }
167
168 private void handleItem(final PropertyReport report, final Class<?> type,
169 final JavaMethod javaMethod)
170 {
171 if (!isPropertyMethod(javaMethod))
172 {
173 return;
174 }
175
176 final PropertyMetaDataParser metaDataParser =
177 PropertyMetaDataParser.createWithoutContextAccess();
178 final PropertyReportItem.Builder builder = new PropertyReportItem.Builder();
179
180 final PropertyDescriptor descriptor =
181 readDescriptor(report, type, javaMethod, metaDataParser);
182 builder.with(descriptor);
183
184 final SourceInfo sourceInfo =
185 new SourceInfo(type.getName(), javaMethod.getName(),
186 javaMethod.getLineNumber());
187 builder.with(sourceInfo);
188
189 final String comment = javaMethod.getComment();
190 builder.withComment(comment);
191
192 final ValueComment valueComment = loadValueComment(report, descriptor);
193 builder.with(valueComment);
194
195 final PropertyReportItem item = builder.build();
196 report.handle(item);
197 }
198
199 private PropertyDescriptor readDescriptor(final PropertyReport report,
200 final Class<?> type, final JavaMethod javaMethod,
201 final PropertyMetaDataParser metaDataParser)
202 {
203 final String methodName = javaMethod.getName();
204 final Method method = getMethod(report, type, methodName);
205 final PropertyDescriptor descriptor = metaDataParser.readDescriptor(method);
206 return descriptor;
207 }
208
209 private Method getMethod(final PropertyReport report, final Class<?> type,
210 final String methodName)
211 {
212 try
213 {
214 final Method method = type.getMethod(methodName, NO_PARAMS);
215 return method;
216 }
217 catch (final Exception e)
218 {
219 report.addProblem(new ReportProblem("Cannot locate method '" + methodName
220 + "' in class '" + type.getName()
221 + "'.", e));
222 return null;
223 }
224 }
225
226 private static boolean isPropertyMethod(final JavaMethod javaMethod)
227 {
228 final int parameterCount = javaMethod.getParameters().size();
229 if (parameterCount != 0)
230 {
231 return false;
232 }
233
234 final String marker = PropertyMetaDataMethod.class.getName();
235 for (final JavaAnnotation annotation : javaMethod.getAnnotations())
236 {
237 if (marker.equals(annotation.getType().getName()))
238 {
239 return true;
240 }
241 }
242
243 final String methodName = javaMethod.getName();
244 final boolean isPropertyMethod =
245 (!(methodName.endsWith(PropertyMetaDataMethod.PROPERTY_KEY) || methodName
246 .endsWith(PropertyMetaDataMethod.PROPERTY_DESCRIPTOR)));
247 return isPropertyMethod;
248 }
249
250 private ValueComment loadValueComment(final PropertyReport report,
251 final PropertyDescriptor descriptor)
252 {
253 final Class<?> type = descriptor.getType().getType();
254
255 if (type.isEnum())
256 {
257 final String typeName = type.getName();
258 final JavaClass javaClass = javaProjectBuilder.getClassByName(typeName);
259 if (javaClass != null)
260 {
261 return loadValueComment(report, javaClass);
262 }
263 else
264 {
265 report.addProblem(new ReportProblem("Cannot find type class '"
266 + typeName + "'."));
267 }
268 }
269
270 return new ValueComment(null);
271 }
272
273 private ValueComment loadValueComment(final PropertyReport report,
274 final JavaClass javaClass)
275 {
276 final String comment = javaClass.getComment();
277 final ValueComment valueComment = new ValueComment(comment);
278
279 for (final JavaField field : javaClass.getEnumConstants())
280 {
281 try
282 {
283 final List<Expression> constantArguments =
284 field.getEnumConstantArguments();
285 final Object instance;
286
287 if (constantArguments.isEmpty())
288 {
289 instance = field.getName();
290 }
291 else
292 {
293
294 final Expression expression = constantArguments.get(0);
295 instance = normalizeExpression(expression);
296 }
297 valueComment.addValueComment(instance, field.getComment());
298 }
299 catch (final Exception e)
300 {
301 report.addProblem(new ReportProblem(
302 "Cannot load field information from type '"
303 + javaClass.getFullyQualifiedName() + "'."));
304 }
305 }
306
307 return valueComment;
308 }
309
310 private static Object normalizeExpression(final Expression expression)
311 {
312 final Object instance;
313 final Object paramValue = expression.getParameterValue();
314 final String valueString = ObjectUtils.toString(paramValue, null);
315 final int length = valueString.length();
316 if (length > 2 && valueString.charAt(0) == '"'
317 && valueString.charAt(length - 1) == '"')
318 {
319 instance = valueString.substring(1, length - 1);
320 }
321 else
322 {
323 instance = expression;
324 }
325 return instance;
326 }
327
328
329
330 }