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