1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.rat.config.parameters;
20
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Map;
26 import java.util.TreeMap;
27 import java.util.function.Predicate;
28 import java.util.stream.Collectors;
29
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.rat.BuilderParams;
32 import org.apache.rat.ConfigurationException;
33 import org.apache.rat.analysis.IHeaderMatcher;
34 import org.apache.rat.utils.Log;
35
36
37
38
39 public class Description {
40
41 private final ComponentType type;
42
43
44
45
46 private final String name;
47
48 private final String desc;
49
50 private final Class<?> childClass;
51
52 private final boolean isCollection;
53
54 private final boolean required;
55
56
57
58
59 private final Map<String, Description> children;
60
61 public static Predicate<Description> typePredicate(ComponentType type) {
62 return (d) -> d.getType() == type;
63 }
64
65
66
67
68
69
70
71
72
73
74
75
76 public Description(ComponentType type, String name, String desc, boolean isCollection, Class<?> childClass,
77 Collection<Description> children, boolean required) {
78 this.type = type;
79 this.name = name;
80 this.desc = desc;
81 this.isCollection = isCollection;
82 this.required = required;
83 if (type == ComponentType.BUILD_PARAMETER) {
84 Method m;
85 try {
86 m = BuilderParams.class.getMethod(name);
87 } catch (NoSuchMethodException | SecurityException e) {
88 throw new ConfigurationException(String.format("'%s' is not a valid BuildParams method", name));
89 }
90 this.childClass = m.getReturnType();
91 } else {
92 this.childClass = childClass;
93 }
94 this.children = new TreeMap<>();
95 if (children != null) {
96 children.forEach(d -> {
97 this.children.put(d.name, d);
98 });
99 }
100 }
101
102
103
104
105
106
107
108
109
110
111 public Description(ConfigComponent configComponent, boolean isCollection, Class<?> childClass,
112 Collection<Description> children) {
113 this(configComponent.type(), configComponent.name(), configComponent.desc(), isCollection, childClass, children,
114 configComponent.required());
115 }
116
117
118
119
120
121
122 public boolean isRequired() {
123 return required;
124 }
125
126
127
128
129
130
131 public ComponentType getType() {
132 return type;
133 }
134
135
136
137
138
139
140 public boolean isCollection() {
141 return isCollection;
142 }
143
144
145
146
147
148
149 public Class<?> getChildType() {
150 return childClass;
151 }
152
153
154
155
156
157
158
159 public String getCommonName() {
160 return name;
161 }
162
163
164
165
166
167
168
169 public String getDescription() {
170 return desc;
171 }
172
173
174
175
176
177
178
179
180
181
182 public String getParamValue(Log log, Object object) {
183 if (isCollection) {
184 return null;
185 }
186 try {
187 Object val = getter(object.getClass()).invoke(object);
188 return val == null ? null : val.toString();
189 } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException | NoSuchMethodException
190 | SecurityException e) {
191 log.error(System.err.format("Can not retrieve value for '%s' from %s%n", name, object.getClass().getName()),
192 e);
193 return null;
194 }
195 }
196
197
198
199
200
201
202
203
204
205 public Map<String, Description> getChildren() {
206 return children;
207 }
208
209
210
211
212
213
214
215 public Collection<Description> childrenOfType(ComponentType type) {
216 return filterChildren(d -> d.getType() == type);
217 }
218
219
220
221
222
223
224
225 public Collection<Description> filterChildren(Predicate<Description> filter) {
226 return children.values().stream().filter(filter).collect(Collectors.toList());
227 }
228
229
230
231
232
233
234
235 public String methodName(String prefix) {
236 return prefix + StringUtils.capitalize(name);
237 }
238
239
240
241
242
243
244
245
246
247 public Method getter(Class<?> clazz) throws NoSuchMethodException, SecurityException {
248 return clazz.getMethod(methodName("get"));
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268 public Method setter(Class<?> clazz) throws NoSuchMethodException, SecurityException {
269 String methodName = methodName(isCollection ? "add" : "set");
270 switch (type) {
271 case LICENSE:
272 throw new NoSuchMethodException("Can not set a License as a child");
273 case MATCHER:
274 return clazz.getMethod(methodName, IHeaderMatcher.Builder.class);
275 case PARAMETER:
276 return clazz.getMethod(methodName,
277 IHeaderMatcher.class.isAssignableFrom(childClass) ? IHeaderMatcher.Builder.class : childClass);
278 case BUILD_PARAMETER:
279 return clazz.getMethod(methodName, childClass);
280 }
281
282 throw new IllegalStateException("Type " + type + " not valid.");
283 }
284
285 private void callSetter(Log log, Description description, IHeaderMatcher.Builder builder, String value) {
286 try {
287 description.setter(builder.getClass()).invoke(builder, value);
288 } catch (NoSuchMethodException e) {
289 String msg = String.format("No setter for '%s' on %s", description.getCommonName(),
290 builder.getClass().getCanonicalName());
291 log.error(msg);
292 throw new ConfigurationException(msg);
293 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException e) {
294 String msg = String.format("Unable to call setter for '%s' on %s", description.getCommonName(),
295 builder.getClass().getCanonicalName());
296 log.error(msg, e);
297 throw new ConfigurationException(msg, e);
298 }
299 }
300
301
302
303
304
305
306
307
308
309
310 public void setChildren(Log log, IHeaderMatcher.Builder builder, Map<String, String> attributes) {
311 attributes.entrySet().forEach(entry -> setChild(log, builder, entry.getKey(), entry.getValue()));
312 }
313
314
315
316
317
318
319
320
321
322 public void setChild(Log log, IHeaderMatcher.Builder builder, String name, String value) {
323 Description d = getChildren().get(name);
324 if (d == null) {
325 log.error(String.format("%s does not define a ConfigComponent for a member %s.",
326 builder.getClass().getCanonicalName(), name));
327 } else {
328 callSetter(log, d, builder, value);
329 }
330 }
331
332 @Override
333 public String toString() {
334 String childList = children.isEmpty() ? ""
335 : String.join(", ",
336 children.values().stream().map(Description::getCommonName).collect(Collectors.toList()));
337
338 return String.format("Description[%s t:%s c:%s %s children: [%s]] ", name, type, isCollection, childClass,
339 childList);
340 }
341
342
343
344
345
346
347
348 public String toString(int indent) {
349 char[] spaces = new char[indent];
350 Arrays.fill(spaces, ' ');
351 String padding = String.copyValueOf(spaces);
352 String top = String.format("%sDescription[ t:%s n:%s c:%s %s%n%s %s] ", padding, type, name, isCollection,
353 childClass, padding, desc);
354 if (children.isEmpty()) {
355 return top;
356 }
357 StringBuilder sb = new StringBuilder(top);
358 for (Description child : children.values()) {
359 sb.append(System.lineSeparator()).append(child.toString(indent + 2));
360 }
361 return sb.toString();
362 }
363 }