1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.rat.configuration;
20
21 import java.io.IOException;
22 import java.io.Writer;
23 import java.lang.reflect.InvocationTargetException;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.HashSet;
27 import java.util.Optional;
28 import java.util.Set;
29 import java.util.SortedSet;
30 import java.util.UUID;
31 import java.util.function.Predicate;
32
33 import org.apache.commons.lang3.StringUtils;
34 import org.apache.rat.ImplementationException;
35 import org.apache.rat.ReportConfiguration;
36 import org.apache.rat.analysis.IHeaderMatcher;
37 import org.apache.rat.api.RatException;
38 import org.apache.rat.config.parameters.ComponentType;
39 import org.apache.rat.config.parameters.Description;
40 import org.apache.rat.configuration.builders.MatcherRefBuilder;
41 import org.apache.rat.license.ILicense;
42 import org.apache.rat.license.ILicenseFamily;
43 import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
44 import org.apache.rat.report.xml.writer.IXmlWriter;
45 import org.apache.rat.report.xml.writer.XmlWriter;
46
47
48
49
50 public class XMLConfigurationWriter {
51
52 private final ReportConfiguration configuration;
53
54 private final Set<String> matchers;
55
56 private final Set<String> licenseChildren;
57
58
59
60
61
62 public XMLConfigurationWriter(final ReportConfiguration configuration) {
63 this.configuration = configuration;
64 this.matchers = new HashSet<>();
65 licenseChildren = new HashSet<>(Arrays.asList(XMLConfig.LICENSE_CHILDREN));
66 }
67
68 private Predicate<Description> attributeFilter(final Description parent) {
69 return d -> {
70 if (d.getType() == ComponentType.PARAMETER) {
71 switch (parent.getType()) {
72 case MATCHER:
73 return !XMLConfig.isInlineNode(parent.getCommonName(), d.getCommonName());
74 case LICENSE:
75 return !licenseChildren.contains(d.getCommonName());
76 default:
77 return true;
78 }
79 }
80 return false;
81 };
82 }
83
84
85
86
87
88
89 public void write(final Writer plainWriter) throws RatException {
90 write(new XmlWriter(plainWriter));
91 }
92
93
94
95
96
97
98 public void write(final IXmlWriter writer) throws RatException {
99 if (configuration.listFamilies() != LicenseFilter.NONE || configuration.listLicenses() != LicenseFilter.NONE) {
100 try {
101 writer.openElement(XMLConfig.ROOT);
102
103
104 SortedSet<ILicenseFamily> families = configuration.getLicenseFamilies(configuration.listFamilies());
105 if (!families.isEmpty()) {
106 writer.openElement(XMLConfig.FAMILIES);
107 for (ILicenseFamily family : families) {
108 writeFamily(writer, family);
109 }
110 writer.closeElement();
111 }
112
113
114 SortedSet<ILicense> licenses = configuration.getLicenses(configuration.listLicenses());
115 if (!licenses.isEmpty()) {
116 writer.openElement(XMLConfig.LICENSES);
117 for (ILicense license : licenses) {
118 writeDescription(writer, license.getDescription(), license);
119 }
120 writer.closeElement();
121 }
122
123
124 writer.openElement(XMLConfig.APPROVED);
125 for (String family : configuration.getLicenseCategories(LicenseFilter.APPROVED)) {
126 writer.openElement(XMLConfig.APPROVED).attribute(XMLConfig.ATT_LICENSE_REF, family.trim())
127 .closeElement();
128 }
129 writer.closeElement();
130
131
132 MatcherBuilderTracker tracker = MatcherBuilderTracker.instance();
133 writer.openElement(XMLConfig.MATCHERS);
134 for (Class<?> clazz : tracker.getClasses()) {
135 writer.openElement(XMLConfig.MATCHER).attribute(XMLConfig.ATT_CLASS_NAME, clazz.getCanonicalName())
136 .closeElement();
137 }
138 writer.closeElement();
139
140 writer.closeElement();
141 } catch (IOException e) {
142 throw new RatException(e);
143 }
144 }
145 }
146
147 private void writeFamily(final IXmlWriter writer, final ILicenseFamily family) throws RatException {
148 try {
149 writer.openElement(XMLConfig.FAMILY).attribute(XMLConfig.ATT_ID, family.getFamilyCategory().trim())
150 .attribute(XMLConfig.ATT_NAME, family.getFamilyName());
151 writer.closeElement();
152 } catch (IOException e) {
153 throw new RatException(e);
154 }
155 }
156
157 private void writeDescriptions(final IXmlWriter writer, final Collection<Description> descriptions, final IHeaderMatcher component)
158 throws RatException {
159 for (Description description : descriptions) {
160 writeDescription(writer, description, component);
161 }
162 }
163
164 private void writeChildren(final IXmlWriter writer, final Description description, final IHeaderMatcher component)
165 throws RatException {
166 writeAttributes(writer, description.filterChildren(attributeFilter(component.getDescription())), component);
167 writeDescriptions(writer, description.filterChildren(attributeFilter(component.getDescription()).negate()),
168 component);
169 }
170
171 private void writeAttributes(final IXmlWriter writer, final Collection<Description> descriptions, final IHeaderMatcher component)
172 throws RatException {
173 for (Description d : descriptions) {
174 try {
175 writeAttribute(writer, d, component);
176 } catch (IOException e) {
177 throw new RatException(e);
178 }
179 }
180 }
181
182 private void writeComment(final IXmlWriter writer, final Description description) throws IOException {
183 if (StringUtils.isNotBlank(description.getDescription())) {
184 writer.comment(description.getDescription());
185 }
186 }
187
188 private void writeAttribute(final IXmlWriter writer, final Description description, final IHeaderMatcher component)
189 throws IOException {
190 String paramValue = description.getParamValue(component);
191 if (paramValue != null) {
192 writer.attribute(description.getCommonName(), paramValue);
193 }
194 }
195
196
197 @SuppressWarnings("unchecked")
198 void writeDescription(final IXmlWriter writer, final Description desc, final IHeaderMatcher comp) throws RatException {
199 Description description = desc;
200 IHeaderMatcher component = comp;
201 try {
202 switch (description.getType()) {
203 case MATCHER:
204
205 Optional<Description> id = description.childrenOfType(ComponentType.PARAMETER).stream()
206 .filter(i -> XMLConfig.ATT_ID.equals(i.getCommonName())).findFirst();
207
208
209 if (id.isPresent()) {
210 String matcherId = id.get().getParamValue(component);
211
212 if (matchers.contains(matcherId)) {
213 component = new MatcherRefBuilder.IHeaderMatcherProxy(matcherId, null);
214 description = component.getDescription();
215 } else {
216 matchers.add(matcherId);
217 }
218
219 try {
220 UUID.fromString(matcherId);
221 description.getChildren().remove(XMLConfig.ATT_ID);
222 } catch (IllegalArgumentException expected) {
223 if (description.getCommonName().equals("spdx")) {
224 description.getChildren().remove(XMLConfig.ATT_ID);
225 }
226 }
227 }
228
229
230 Optional<Description> resource = description.childrenOfType(ComponentType.PARAMETER).stream()
231 .filter(i -> XMLConfig.ATT_RESOURCE.equals(i.getCommonName())).findFirst();
232 if (resource.isPresent()) {
233 String resourceStr = resource.get().getParamValue(component);
234 if (StringUtils.isNotBlank(resourceStr)) {
235 description.getChildren().remove("enclosed");
236 }
237 }
238 writeComment(writer, description);
239 writer.openElement(description.getCommonName());
240 writeChildren(writer, description, component);
241 writer.closeElement();
242 break;
243 case LICENSE:
244 writer.openElement(XMLConfig.LICENSE);
245 writeChildren(writer, description, component);
246 writer.closeElement();
247 break;
248 case PARAMETER:
249 if ("id".equals(description.getCommonName())) {
250 try {
251 String paramId = description.getParamValue(component);
252
253 if (paramId != null) {
254 UUID.fromString(paramId);
255 return;
256 }
257 } catch (IllegalArgumentException expected) {
258
259 }
260 }
261 if (description.getChildType() == String.class) {
262
263 boolean inline = XMLConfig.isInlineNode(component.getDescription().getCommonName(),
264 description.getCommonName());
265 String s = description.getParamValue(component);
266 if (StringUtils.isNotBlank(s)) {
267 if (!inline) {
268 writer.openElement(description.getCommonName());
269 }
270 writer.content(description.getParamValue(component));
271 if (!inline) {
272 writer.closeElement();
273 }
274 }
275 } else {
276 try {
277 if (description.isCollection()) {
278 for (IHeaderMatcher matcher : (Collection<IHeaderMatcher>) description
279 .getter(component.getClass()).invoke(component)) {
280 writeDescription(writer, matcher.getDescription(), matcher);
281 }
282 } else {
283 IHeaderMatcher matcher = (IHeaderMatcher) description.getter(component.getClass())
284 .invoke(component);
285 writeDescription(writer, matcher.getDescription(), matcher);
286 }
287 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
288 | NoSuchMethodException | SecurityException | RatException e) {
289 throw new ImplementationException(e);
290 }
291 }
292 break;
293 case BUILD_PARAMETER:
294
295 break;
296 }
297 } catch (IOException e) {
298 throw new RatException(e);
299 }
300 }
301 }