1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.assembly.filter;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.Reader;
24 import java.io.StringReader;
25 import java.io.StringWriter;
26 import java.nio.file.Files;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.LinkedHashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.NoSuchElementException;
33 import java.util.zip.ZipEntry;
34 import java.util.zip.ZipFile;
35
36 import org.codehaus.plexus.archiver.ArchiveEntry;
37 import org.codehaus.plexus.archiver.ArchivedFileSet;
38 import org.codehaus.plexus.archiver.Archiver;
39 import org.codehaus.plexus.archiver.ArchiverException;
40 import org.codehaus.plexus.archiver.FileSet;
41 import org.codehaus.plexus.archiver.ResourceIterator;
42 import org.codehaus.plexus.archiver.diags.NoOpArchiver;
43 import org.codehaus.plexus.archiver.zip.ZipArchiver;
44 import org.codehaus.plexus.components.io.resources.PlexusIoResource;
45 import org.codehaus.plexus.components.io.resources.PlexusIoResourceCollection;
46 import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
47 import org.codehaus.plexus.util.xml.Xpp3Dom;
48 import org.jdom2.Document;
49 import org.jdom2.Text;
50 import org.jdom2.filter.Filters;
51 import org.jdom2.input.SAXBuilder;
52 import org.jdom2.input.sax.XMLReaders;
53 import org.jdom2.xpath.XPathExpression;
54 import org.jdom2.xpath.XPathFactory;
55 import org.junit.jupiter.api.BeforeEach;
56 import org.junit.jupiter.api.Test;
57 import org.junit.jupiter.api.io.TempDir;
58
59 import static org.junit.jupiter.api.Assertions.assertEquals;
60 import static org.junit.jupiter.api.Assertions.assertFalse;
61 import static org.junit.jupiter.api.Assertions.assertNotNull;
62 import static org.junit.jupiter.api.Assertions.assertNull;
63
64 public class ComponentsXmlArchiverFileFilterTest {
65
66 @TempDir
67 private File temporaryFolder;
68
69 private ComponentsXmlArchiverFileFilter filter;
70
71 @BeforeEach
72 public void setUp() {
73 filter = new ComponentsXmlArchiverFileFilter();
74 }
75
76 @Test
77 public void testAddComponentsXmlShouldAddComponentWithoutRoleHint() throws Exception {
78 final Reader reader =
79 writeComponentsXml(Collections.singletonList(new ComponentDef("role", null, "org.apache.maven.Impl")));
80
81 filter.addComponentsXml(reader);
82
83 assertFalse(filter.components.isEmpty());
84
85 final Xpp3Dom componentDom = filter.components.get("role");
86
87 assertEquals("role", componentDom.getChild("role").getValue());
88 assertNull(componentDom.getChild("role-hint"));
89 assertEquals(
90 "org.apache.maven.Impl", componentDom.getChild("implementation").getValue());
91 }
92
93 @Test
94 public void testAddComponentsXmlShouldAddComponentWithRoleHint() throws Exception {
95 final Reader reader = writeComponentsXml(
96 Collections.singletonList(new ComponentDef("role", "hint", "org.apache.maven.Impl")));
97
98 filter.addComponentsXml(reader);
99
100 assertFalse(filter.components.isEmpty());
101
102 final Xpp3Dom componentDom = filter.components.get("rolehint");
103
104 assertEquals("role", componentDom.getChild("role").getValue());
105 assertEquals("hint", componentDom.getChild("role-hint").getValue());
106 assertEquals(
107 "org.apache.maven.Impl", componentDom.getChild("implementation").getValue());
108 }
109
110 @Test
111 public void testAddComponentsXmlShouldAddTwoComponentsWithRoleHints() throws Exception {
112 final List<ComponentDef> defs = new ArrayList<>();
113
114 defs.add(new ComponentDef("role", "hint", "org.apache.maven.Impl"));
115 defs.add(new ComponentDef("role", "hint2", "org.apache.maven.Impl2"));
116
117 final Reader reader = writeComponentsXml(defs);
118
119 filter.addComponentsXml(reader);
120
121 assertFalse(filter.components.isEmpty());
122
123 Xpp3Dom componentDom = filter.components.get("rolehint");
124
125 assertEquals("role", componentDom.getChild("role").getValue());
126 assertEquals("hint", componentDom.getChild("role-hint").getValue());
127 assertEquals(
128 "org.apache.maven.Impl", componentDom.getChild("implementation").getValue());
129
130 componentDom = filter.components.get("rolehint2");
131
132 assertEquals("role", componentDom.getChild("role").getValue());
133 assertEquals("hint2", componentDom.getChild("role-hint").getValue());
134 assertEquals(
135 "org.apache.maven.Impl2",
136 componentDom.getChild("implementation").getValue());
137 }
138
139 @Test
140 public void testAddToArchiveShouldWriteComponentWithoutHintToFile() throws Exception {
141 final Xpp3Dom dom = createComponentDom(new ComponentDef("role", null, "impl"));
142
143 filter.components = new LinkedHashMap<>();
144 filter.components.put("role", dom);
145
146 final FileCatchingArchiver fca = new FileCatchingArchiver();
147
148 filter.finalizeArchiveCreation(fca);
149
150 assertEquals(ComponentsXmlArchiverFileFilter.COMPONENTS_XML_PATH, fca.getDestFileName());
151
152 final SAXBuilder builder = new SAXBuilder(XMLReaders.NONVALIDATING);
153
154 final Document doc = builder.build(fca.getFile());
155 XPathFactory xPathFactory = XPathFactory.instance();
156
157 XPathExpression<Text> role = xPathFactory.compile("//component[position()=1]/role/text()", Filters.text());
158 XPathExpression<Text> hint = xPathFactory.compile("//component[position()=1]/role-hint/text()", Filters.text());
159 XPathExpression<Text> implementation =
160 xPathFactory.compile("//component[position()=1]/implementation/text()", Filters.text());
161
162 assertEquals("role", role.evaluateFirst(doc).getText());
163 assertNull(hint.evaluateFirst(doc));
164 assertEquals("impl", implementation.evaluateFirst(doc).getText());
165 }
166
167 @Test
168 public void testAddToArchiveShouldWriteComponentWithHintToFile() throws Exception {
169 final Xpp3Dom dom = createComponentDom(new ComponentDef("role", "hint", "impl"));
170
171 filter.components = new LinkedHashMap<>();
172 filter.components.put("rolehint", dom);
173
174 final FileCatchingArchiver fca = new FileCatchingArchiver();
175
176 filter.finalizeArchiveCreation(fca);
177
178 assertEquals(ComponentsXmlArchiverFileFilter.COMPONENTS_XML_PATH, fca.getDestFileName());
179
180 final SAXBuilder builder = new SAXBuilder(XMLReaders.NONVALIDATING);
181
182 final Document doc = builder.build(fca.getFile());
183 XPathFactory xPathFactory = XPathFactory.instance();
184
185 XPathExpression<Text> role = xPathFactory.compile("//component[position()=1]/role/text()", Filters.text());
186 XPathExpression<Text> hint = xPathFactory.compile("//component[position()=1]/role-hint/text()", Filters.text());
187 XPathExpression<Text> implementation =
188 xPathFactory.compile("//component[position()=1]/implementation/text()", Filters.text());
189
190 assertEquals("role", role.evaluateFirst(doc).getText());
191 assertEquals("hint", hint.evaluateFirst(doc).getText());
192 assertEquals("impl", implementation.evaluateFirst(doc).getText());
193 }
194
195 @Test
196 public void testAddToArchiveShouldWriteTwoComponentToFile() throws Exception {
197 filter.components = new LinkedHashMap<>();
198
199 final Xpp3Dom dom = createComponentDom(new ComponentDef("role", "hint", "impl"));
200
201 filter.components.put("rolehint", dom);
202
203 final Xpp3Dom dom2 = createComponentDom(new ComponentDef("role", "hint2", "impl"));
204
205 filter.components.put("rolehint2", dom2);
206
207 final FileCatchingArchiver fca = new FileCatchingArchiver();
208
209 filter.finalizeArchiveCreation(fca);
210
211 assertEquals(ComponentsXmlArchiverFileFilter.COMPONENTS_XML_PATH, fca.getDestFileName());
212
213 final SAXBuilder builder = new SAXBuilder(XMLReaders.NONVALIDATING);
214
215 final Document doc = builder.build(fca.getFile());
216 XPathFactory xPathFactory = XPathFactory.instance();
217
218 XPathExpression<Text> role = xPathFactory.compile("//component[position()=1]/role/text()", Filters.text());
219 XPathExpression<Text> hint = xPathFactory.compile("//component[position()=1]/role-hint/text()", Filters.text());
220 XPathExpression<Text> implementation =
221 xPathFactory.compile("//component[position()=1]/implementation/text()", Filters.text());
222
223 assertEquals("role", role.evaluateFirst(doc).getText());
224 assertEquals("hint", hint.evaluateFirst(doc).getText());
225 assertEquals("impl", implementation.evaluateFirst(doc).getText());
226
227 XPathExpression<Text> role2 = xPathFactory.compile("//component[position()=2]/role/text()", Filters.text());
228 XPathExpression<Text> hint2 =
229 xPathFactory.compile("//component[position()=2]/role-hint/text()", Filters.text());
230 XPathExpression<Text> implementation2 =
231 xPathFactory.compile("//component[position()=2]/implementation/text()", Filters.text());
232
233 assertEquals("role", role2.evaluateFirst(doc).getText());
234 assertEquals("hint2", hint2.evaluateFirst(doc).getText());
235 assertEquals("impl", implementation2.evaluateFirst(doc).getText());
236 }
237
238 @Test
239 public void testAddToArchiveShouldWriteTwoComponentToArchivedFile() throws Exception {
240 filter.components = new LinkedHashMap<>();
241
242 final Xpp3Dom dom = createComponentDom(new ComponentDef("role", "hint", "impl"));
243
244 filter.components.put("rolehint", dom);
245
246 final Xpp3Dom dom2 = createComponentDom(new ComponentDef("role", "hint2", "impl"));
247
248 filter.components.put("rolehint2", dom2);
249
250 final ZipArchiver archiver = new ZipArchiver();
251
252 final File archiveFile = newFile(temporaryFolder, "archive");
253
254 archiver.setDestFile(archiveFile);
255
256 final File descriptorFile = new File(temporaryFolder, "descriptor.xml");
257
258 archiver.setArchiveFinalizers(Collections.singletonList(filter));
259
260 archiver.createArchive();
261
262 try (ZipFile zf = new ZipFile(archiveFile)) {
263 final ZipEntry ze = zf.getEntry(ComponentsXmlArchiverFileFilter.COMPONENTS_XML_PATH);
264
265 assertNotNull(ze);
266
267 Files.copy(zf.getInputStream(ze), descriptorFile.toPath());
268 }
269
270 final SAXBuilder builder = new SAXBuilder(XMLReaders.NONVALIDATING);
271
272 final Document doc = builder.build(descriptorFile);
273
274 XPathFactory xPathFactory = XPathFactory.instance();
275 XPathExpression<Text> role = xPathFactory.compile("//component[position()=1]/role/text()", Filters.text());
276 XPathExpression<Text> hint = xPathFactory.compile("//component[position()=1]/role-hint/text()", Filters.text());
277 XPathExpression<Text> implementation =
278 xPathFactory.compile("//component[position()=1]/implementation/text()", Filters.text());
279
280 assertEquals("role", role.evaluateFirst(doc).getText());
281 assertEquals("hint", hint.evaluateFirst(doc).getText());
282 assertEquals("impl", implementation.evaluateFirst(doc).getText());
283
284 XPathExpression<Text> role2 = xPathFactory.compile("//component[position()=2]/role/text()", Filters.text());
285 XPathExpression<Text> hint2 =
286 xPathFactory.compile("//component[position()=2]/role-hint/text()", Filters.text());
287 XPathExpression<Text> implementation2 =
288 xPathFactory.compile("//component[position()=2]/implementation/text()", Filters.text());
289
290 assertEquals("role", role2.evaluateFirst(doc).getText());
291 assertEquals("hint2", hint2.evaluateFirst(doc).getText());
292 assertEquals("impl", implementation2.evaluateFirst(doc).getText());
293 }
294
295 private Xpp3Dom createComponentDom(final ComponentDef def) {
296 final Xpp3Dom dom = new Xpp3Dom("component");
297
298 final Xpp3Dom role = new Xpp3Dom("role");
299 role.setValue(def.role);
300 dom.addChild(role);
301
302 final String hint = def.roleHint;
303 if (hint != null) {
304 final Xpp3Dom roleHint = new Xpp3Dom("role-hint");
305 roleHint.setValue(hint);
306 dom.addChild(roleHint);
307 }
308
309 final Xpp3Dom impl = new Xpp3Dom("implementation");
310 impl.setValue(def.implementation);
311 dom.addChild(impl);
312
313 return dom;
314 }
315
316 private Reader writeComponentsXml(final List<ComponentDef> componentDefs) throws IOException {
317 final StringWriter writer = new StringWriter();
318
319 final PrettyPrintXMLWriter xmlWriter = new PrettyPrintXMLWriter(writer);
320
321 xmlWriter.startElement("component-set");
322 xmlWriter.startElement("components");
323
324 for (final ComponentDef def : componentDefs) {
325 xmlWriter.startElement("component");
326
327 xmlWriter.startElement("role");
328 xmlWriter.writeText(def.role);
329 xmlWriter.endElement();
330
331 final String roleHint = def.roleHint;
332 if (roleHint != null) {
333 xmlWriter.startElement("role-hint");
334 xmlWriter.writeText(roleHint);
335 xmlWriter.endElement();
336 }
337
338 xmlWriter.startElement("implementation");
339 xmlWriter.writeText(def.implementation);
340 xmlWriter.endElement();
341
342 xmlWriter.endElement();
343 }
344
345 xmlWriter.endElement();
346 xmlWriter.endElement();
347
348 return new StringReader(writer.toString());
349 }
350
351 private static final class ComponentDef {
352 final String role;
353
354 final String roleHint;
355
356 final String implementation;
357
358 ComponentDef(final String role, final String roleHint, final String implementation) {
359 this.role = role;
360 this.roleHint = roleHint;
361 this.implementation = implementation;
362 }
363 }
364
365 private static final class FileCatchingArchiver extends NoOpArchiver {
366
367 private File inputFile;
368
369 private String destFileName;
370
371 public void addDirectory(final File directory) throws ArchiverException {
372 throw new UnsupportedOperationException("not supported");
373 }
374
375 public void addDirectory(final File directory, final String prefix) throws ArchiverException {
376 throw new UnsupportedOperationException("not supported");
377 }
378
379 public void addDirectory(final File directory, final String[] includes, final String[] excludes)
380 throws ArchiverException {
381 throw new UnsupportedOperationException("not supported");
382 }
383
384 public void addDirectory(
385 final File directory, final String prefix, final String[] includes, final String[] excludes)
386 throws ArchiverException {
387 throw new UnsupportedOperationException("not supported");
388 }
389
390 public void addFile(final File inputFile, final String destFileName) throws ArchiverException {
391 this.inputFile = inputFile;
392 this.destFileName = destFileName;
393 }
394
395 File getFile() {
396 return inputFile;
397 }
398
399 String getDestFileName() {
400 return destFileName;
401 }
402
403 public void addFile(final File inputFile, final String destFileName, final int permissions)
404 throws ArchiverException {
405 throw new UnsupportedOperationException("not supported");
406 }
407
408 public void createArchive() throws ArchiverException, IOException {
409 throw new UnsupportedOperationException("not supported");
410 }
411
412 public int getDefaultDirectoryMode() {
413 throw new UnsupportedOperationException("not supported");
414 }
415
416 public void setDefaultDirectoryMode(final int mode) {
417 throw new UnsupportedOperationException("not supported");
418 }
419
420 public int getDefaultFileMode() {
421 throw new UnsupportedOperationException("not supported");
422 }
423
424 public void setDefaultFileMode(final int mode) {
425 throw new UnsupportedOperationException("not supported");
426 }
427
428 public File getDestFile() {
429 throw new UnsupportedOperationException("not supported");
430 }
431
432 public void setDestFile(final File destFile) {
433 throw new UnsupportedOperationException("not supported");
434 }
435
436 public void addSymlink(String s, String s2) throws ArchiverException {
437 throw new UnsupportedOperationException("not supported");
438 }
439
440 public void addSymlink(String s, int i, String s2) throws ArchiverException {
441 throw new UnsupportedOperationException("not supported");
442 }
443
444 public Map<String, ArchiveEntry> getFiles() {
445 throw new UnsupportedOperationException("not supported");
446 }
447
448 public boolean getIncludeEmptyDirs() {
449 throw new UnsupportedOperationException("not supported");
450 }
451
452 public void setIncludeEmptyDirs(final boolean includeEmptyDirs) {
453 throw new UnsupportedOperationException("not supported");
454 }
455
456 public void addArchivedFileSet(final File archiveFile) throws ArchiverException {
457 throw new UnsupportedOperationException("not supported");
458 }
459
460 public void addArchivedFileSet(final File archiveFile, final String prefix) throws ArchiverException {
461 throw new UnsupportedOperationException("not supported");
462 }
463
464 public void addArchivedFileSet(final File archiveFile, final String[] includes, final String[] excludes)
465 throws ArchiverException {
466 throw new UnsupportedOperationException("not supported");
467 }
468
469 public void addArchivedFileSet(
470 final File archiveFile, final String prefix, final String[] includes, final String[] excludes)
471 throws ArchiverException {
472 throw new UnsupportedOperationException("not supported");
473 }
474
475 public boolean isForced() {
476 throw new UnsupportedOperationException("not supported");
477 }
478
479 public void setForced(final boolean forced) {
480 throw new UnsupportedOperationException("not supported");
481 }
482
483 public boolean isSupportingForced() {
484 throw new UnsupportedOperationException("not supported");
485 }
486
487 public void setDotFileDirectory(final File dotFileDirectory) {}
488
489 public void addArchivedFileSet(final ArchivedFileSet fileSet) throws ArchiverException {
490 throw new UnsupportedOperationException("not supported");
491 }
492
493 public void addFileSet(final FileSet fileSet) throws ArchiverException {
494 throw new UnsupportedOperationException("not supported");
495 }
496
497 public void addResource(final PlexusIoResource resource, final String destFileName, final int permissions)
498 throws ArchiverException {
499 throw new UnsupportedOperationException("not supported");
500 }
501
502 public void addResources(final PlexusIoResourceCollection resources) throws ArchiverException {
503 throw new UnsupportedOperationException("not supported");
504 }
505
506 public ResourceIterator getResources() throws ArchiverException {
507 return new ResourceIterator() {
508
509 public boolean hasNext() throws ArchiverException {
510 return false;
511 }
512
513 public ArchiveEntry next() throws ArchiverException {
514 throw new NoSuchElementException();
515 }
516
517 public void remove() {
518 throw new NoSuchElementException();
519 }
520 };
521 }
522
523 public String getDuplicateBehavior() {
524 return Archiver.DUPLICATES_ADD;
525 }
526
527 public void setDuplicateBehavior(final String duplicate) {}
528
529 public int getDirectoryMode() {
530 throw new UnsupportedOperationException("not supported");
531 }
532
533 public void setDirectoryMode(final int mode) {
534 throw new UnsupportedOperationException("not supported");
535 }
536
537 public int getFileMode() {
538 throw new UnsupportedOperationException("not supported");
539 }
540
541 public void setFileMode(final int mode) {
542 throw new UnsupportedOperationException("not supported");
543 }
544
545 public int getOverrideDirectoryMode() {
546 throw new UnsupportedOperationException("not supported");
547 }
548
549 public int getOverrideFileMode() {
550 throw new UnsupportedOperationException("not supported");
551 }
552 }
553
554 private static File newFile(File parent, String child) throws IOException {
555 File result = new File(parent, child);
556 result.createNewFile();
557 return result;
558 }
559 }