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  
20  package org.apache.maven.plugins.shade.resource;
21  
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertNotNull;
24  import static org.junit.Assert.assertTrue;
25  
26  import java.io.ByteArrayInputStream;
27  import java.io.File;
28  import java.io.FileOutputStream;
29  import java.io.InputStream;
30  import java.nio.charset.StandardCharsets;
31  import java.util.ArrayList;
32  import java.util.Arrays;
33  import java.util.Collections;
34  import java.util.List;
35  import java.util.jar.JarEntry;
36  import java.util.jar.JarFile;
37  import java.util.jar.JarOutputStream;
38  
39  import org.apache.commons.io.IOUtils;
40  import org.apache.maven.plugins.shade.relocation.Relocator;
41  import org.apache.maven.plugins.shade.relocation.SimpleRelocator;
42  import org.junit.Test;
43  
44  /**
45   * Test for handling META-INF/service/...
46   */
47  public class ServiceResourceTransformerTest {
48      private final String NEWLINE = "\n";
49  
50      private List<Relocator> relocators = new ArrayList<Relocator>();
51  
52      @Test
53      public void relocatedClasses() throws Exception {
54          SimpleRelocator relocator =
55              new SimpleRelocator( "org.foo", "borg.foo", null, Arrays.asList( "org.foo.exclude.*" ) );
56          relocators.add( relocator );
57  
58          String content = "org.foo.Service\norg.foo.exclude.OtherService\n";
59          byte[] contentBytes = content.getBytes( StandardCharsets.UTF_8 );
60          InputStream contentStream = new ByteArrayInputStream( contentBytes );
61          String contentResource = "META-INF/services/org.foo.something.another";
62          String contentResourceShaded = "META-INF/services/borg.foo.something.another";
63  
64          ServicesResourceTransformer xformer = new ServicesResourceTransformer();
65          xformer.processResource( contentResource, contentStream, relocators, 0 );
66          contentStream.close();
67  
68          File tempJar = File.createTempFile("shade.", ".jar");
69          tempJar.deleteOnExit();
70          FileOutputStream fos = new FileOutputStream( tempJar );
71          try ( JarOutputStream jos = new JarOutputStream( fos ) ) {
72              xformer.modifyOutputStream( jos );
73              jos.close();
74              
75              JarFile jarFile = new JarFile( tempJar );
76              JarEntry jarEntry = jarFile.getJarEntry( contentResourceShaded );
77              assertNotNull( jarEntry );
78              try ( InputStream entryStream = jarFile.getInputStream( jarEntry ) ) {
79                  String xformedContent = IOUtils.toString( entryStream, "utf-8" );
80                  assertEquals( "borg.foo.Service" + NEWLINE
81                      + "org.foo.exclude.OtherService" + NEWLINE, xformedContent );
82              } finally {
83                  jarFile.close();
84              }
85          } finally {
86              tempJar.delete();
87          }
88      }
89  
90      @Test
91      public void mergeRelocatedFiles() throws Exception {
92          SimpleRelocator relocator =
93                  new SimpleRelocator( "org.foo", "borg.foo", null, Collections.singletonList("org.foo.exclude.*"));
94          relocators.add( relocator );
95  
96          String content = "org.foo.Service" + NEWLINE + "org.foo.exclude.OtherService" + NEWLINE;
97          String contentShaded = "borg.foo.Service" + NEWLINE + "org.foo.exclude.OtherService" + NEWLINE;
98          byte[] contentBytes = content.getBytes( StandardCharsets.UTF_8 );
99          String contentResource = "META-INF/services/org.foo.something.another";
100         String contentResourceShaded = "META-INF/services/borg.foo.something.another";
101 
102         ServicesResourceTransformer xformer = new ServicesResourceTransformer();
103 
104         try (InputStream contentStream = new ByteArrayInputStream( contentBytes )) {
105             xformer.processResource(contentResource, contentStream, relocators, 0);
106         }
107 
108         try (InputStream contentStream = new ByteArrayInputStream( contentBytes )) {
109             xformer.processResource(contentResourceShaded, contentStream, relocators, 0);
110         }
111 
112         File tempJar = File.createTempFile("shade.", ".jar");
113         tempJar.deleteOnExit();
114         FileOutputStream fos = new FileOutputStream( tempJar );
115         try ( JarOutputStream jos = new JarOutputStream( fos ) ) {
116             xformer.modifyOutputStream( jos );
117             jos.close();
118 
119             JarFile jarFile = new JarFile( tempJar );
120             JarEntry jarEntry = jarFile.getJarEntry( contentResourceShaded );
121             assertNotNull( jarEntry );
122             try ( InputStream entryStream = jarFile.getInputStream( jarEntry ) ) {
123                 String xformedContent = IOUtils.toString( entryStream, StandardCharsets.UTF_8);
124                 assertEquals( contentShaded, xformedContent );
125             } finally {
126                 jarFile.close();
127             }
128         } finally {
129             tempJar.delete();
130         }
131     }
132     
133     @Test
134     public void concatanationAppliedMultipleTimes() throws Exception {
135         SimpleRelocator relocator =
136             new SimpleRelocator( "org.eclipse", "org.eclipse1234", null, null );
137         relocators.add( relocator );
138         
139         String content = "org.eclipse.osgi.launch.EquinoxFactory\n";
140         byte[] contentBytes = content.getBytes( "UTF-8" );
141         InputStream contentStream = new ByteArrayInputStream( contentBytes );
142         String contentResource = "META-INF/services/org.osgi.framework.launch.FrameworkFactory";
143 
144         ServicesResourceTransformer xformer = new ServicesResourceTransformer();
145         xformer.processResource( contentResource, contentStream, relocators, 0 );
146         contentStream.close();
147 
148         File tempJar = File.createTempFile("shade.", ".jar");
149         tempJar.deleteOnExit();
150         FileOutputStream fos = new FileOutputStream( tempJar );
151         try ( JarOutputStream jos = new JarOutputStream( fos ) ) {
152             xformer.modifyOutputStream( jos );
153             jos.close();
154             
155             JarFile jarFile = new JarFile( tempJar );
156             JarEntry jarEntry = jarFile.getJarEntry( contentResource );
157             assertNotNull( jarEntry );
158             try ( InputStream entryStream = jarFile.getInputStream( jarEntry ) ) {
159                 String xformedContent = IOUtils.toString(entryStream, StandardCharsets.UTF_8);
160                 assertEquals( "org.eclipse1234.osgi.launch.EquinoxFactory" + NEWLINE, xformedContent );
161             } finally {
162                 jarFile.close();
163             }
164         } finally {
165             tempJar.delete();
166         }
167     }
168 
169     @Test
170     public void concatenation() throws Exception {
171         SimpleRelocator relocator = new SimpleRelocator("org.foo", "borg.foo", null, null);
172         relocators.add( relocator );
173         
174         String content = "org.foo.Service\n";
175         byte[] contentBytes = content.getBytes( StandardCharsets.UTF_8 );
176         InputStream contentStream = new ByteArrayInputStream( contentBytes );
177         String contentResource = "META-INF/services/org.something.another";
178 
179         ServicesResourceTransformer xformer = new ServicesResourceTransformer();
180         xformer.processResource( contentResource, contentStream, relocators, 0 );
181         contentStream.close();
182 
183         content = "org.blah.Service\n";
184         contentBytes = content.getBytes( StandardCharsets.UTF_8 );
185         contentStream = new ByteArrayInputStream( contentBytes );
186         contentResource = "META-INF/services/org.something.another";
187 
188         xformer.processResource( contentResource, contentStream, relocators, 0 );
189         contentStream.close();
190 
191         File tempJar = File.createTempFile("shade.", ".jar");
192         tempJar.deleteOnExit();
193         FileOutputStream fos = new FileOutputStream( tempJar );
194         try ( JarOutputStream jos = new JarOutputStream( fos ) ) {
195             xformer.modifyOutputStream( jos );
196             jos.close();
197 
198             JarFile jarFile = new JarFile( tempJar );
199             JarEntry jarEntry = jarFile.getJarEntry( contentResource );
200             assertNotNull( jarEntry );
201             try ( InputStream entryStream = jarFile.getInputStream( jarEntry ) ) {
202                 String xformedContent = IOUtils.toString(entryStream, "utf-8");
203                 // must be two lines, with our two classes.
204                 String[] classes = xformedContent.split("\r?\n");
205                 boolean h1 = false;
206                 boolean h2 = false;
207                 for ( String name : classes )
208                 {
209                     if ("org.blah.Service".equals( name ))
210                     {
211                         h1 = true;
212                     }
213                     else if ("borg.foo.Service".equals( name ))
214                     {
215                         h2 = true;
216                     }
217                 }
218                 assertTrue( h1 && h2 );
219             } finally {
220                 jarFile.close();
221             }
222         } finally {
223             tempJar.delete();
224         }
225     }
226 }