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