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