1 | |
package org.apache.maven.plugins.shade; |
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
import java.io.File; |
23 | |
import java.io.FileOutputStream; |
24 | |
import java.io.IOException; |
25 | |
import java.io.InputStream; |
26 | |
import java.util.Enumeration; |
27 | |
import java.util.HashSet; |
28 | |
import java.util.Iterator; |
29 | |
import java.util.List; |
30 | |
import java.util.Set; |
31 | |
import java.util.ArrayList; |
32 | |
import java.util.jar.JarEntry; |
33 | |
import java.util.jar.JarFile; |
34 | |
import java.util.jar.JarOutputStream; |
35 | |
import java.util.zip.ZipException; |
36 | |
|
37 | |
import org.apache.maven.plugins.shade.relocation.Relocator; |
38 | |
import org.apache.maven.plugins.shade.resource.ResourceTransformer; |
39 | |
import org.apache.maven.plugins.shade.filter.Filter; |
40 | |
import org.codehaus.plexus.logging.AbstractLogEnabled; |
41 | |
import org.codehaus.plexus.util.IOUtil; |
42 | |
import org.objectweb.asm.ClassReader; |
43 | |
import org.objectweb.asm.ClassVisitor; |
44 | |
import org.objectweb.asm.ClassWriter; |
45 | |
import org.objectweb.asm.commons.Remapper; |
46 | |
import org.objectweb.asm.commons.RemappingClassAdapter; |
47 | |
|
48 | |
|
49 | |
|
50 | |
|
51 | |
|
52 | 7 | public class DefaultShader |
53 | |
extends AbstractLogEnabled |
54 | |
implements Shader |
55 | |
{ |
56 | |
public void shade( Set jars, File uberJar, List filters, List relocators, List resourceTransformers ) |
57 | |
throws IOException |
58 | |
{ |
59 | 7 | Set resources = new HashSet(); |
60 | |
|
61 | 7 | RelocatorRemapper remapper = new RelocatorRemapper( relocators ); |
62 | |
|
63 | 7 | uberJar.getParentFile().mkdirs(); |
64 | 7 | JarOutputStream jos = new JarOutputStream( new FileOutputStream( uberJar ) ); |
65 | |
|
66 | 7 | for ( Iterator i = jars.iterator(); i.hasNext(); ) |
67 | |
{ |
68 | 12 | File jar = (File) i.next(); |
69 | |
|
70 | 12 | List jarFilters = getFilters( jar, filters ); |
71 | |
|
72 | 12 | JarFile jarFile = new JarFile( jar ); |
73 | |
|
74 | 12 | for ( Enumeration j = jarFile.entries(); j.hasMoreElements(); ) |
75 | |
{ |
76 | 631 | JarEntry entry = (JarEntry) j.nextElement(); |
77 | |
|
78 | 631 | String name = entry.getName(); |
79 | 631 | if ( "META-INF/INDEX.LIST".equals( name ) ) |
80 | |
{ |
81 | |
|
82 | |
|
83 | |
|
84 | 0 | continue; |
85 | |
} |
86 | |
|
87 | 631 | String mappedName = remapper.map( name ); |
88 | |
|
89 | 631 | InputStream is = jarFile.getInputStream( entry ); |
90 | 631 | if ( !entry.isDirectory() && !isFiltered( jarFilters, name ) ) |
91 | |
{ |
92 | 483 | int idx = mappedName.lastIndexOf( '/' ); |
93 | 483 | if ( idx != -1 ) |
94 | |
{ |
95 | |
|
96 | 483 | String dir = mappedName.substring( 0, idx ); |
97 | 483 | if ( !resources.contains( dir ) ) |
98 | |
{ |
99 | 81 | addDirectory( resources, jos, dir ); |
100 | |
} |
101 | |
} |
102 | |
|
103 | 483 | if ( name.endsWith( ".class" ) ) |
104 | |
{ |
105 | 422 | addRemappedClass( remapper, jos, jar, name, is ); |
106 | |
} |
107 | |
else |
108 | |
{ |
109 | 61 | if ( !resourceTransformed( resourceTransformers, mappedName, is ) ) |
110 | |
{ |
111 | |
|
112 | 56 | if ( resources.contains( mappedName ) ) |
113 | |
{ |
114 | 5 | continue; |
115 | |
} |
116 | |
|
117 | 51 | addResource( resources, jos, mappedName, is ); |
118 | |
} |
119 | |
} |
120 | |
} |
121 | |
|
122 | 626 | IOUtil.close( is ); |
123 | |
} |
124 | |
|
125 | 12 | jarFile.close(); |
126 | |
} |
127 | |
|
128 | 7 | for ( Iterator i = resourceTransformers.iterator(); i.hasNext(); ) |
129 | |
{ |
130 | 5 | ResourceTransformer transformer = (ResourceTransformer) i.next(); |
131 | |
|
132 | 5 | if ( transformer.hasTransformedResource() ) |
133 | |
{ |
134 | 5 | transformer.modifyOutputStream( jos ); |
135 | |
} |
136 | |
} |
137 | |
|
138 | 7 | IOUtil.close( jos ); |
139 | 7 | } |
140 | |
|
141 | |
private List getFilters( File jar, List filters ) |
142 | |
{ |
143 | 12 | List list = new ArrayList(); |
144 | |
|
145 | 12 | for ( int i = 0; i < filters.size(); i++ ) |
146 | |
{ |
147 | 0 | Filter filter = (Filter) filters.get( i ); |
148 | |
|
149 | 0 | if ( filter.canFilter( jar ) ) |
150 | |
{ |
151 | 0 | list.add( filter ); |
152 | |
} |
153 | |
|
154 | |
} |
155 | |
|
156 | 12 | return list; |
157 | |
} |
158 | |
|
159 | |
private void addDirectory( Set resources, JarOutputStream jos, String name ) |
160 | |
throws IOException |
161 | |
{ |
162 | 150 | if ( name.lastIndexOf( '/' ) > 0 ) |
163 | |
{ |
164 | 129 | String parent = name.substring( 0, name.lastIndexOf( '/' ) ); |
165 | 129 | if ( !resources.contains( parent ) ) |
166 | |
{ |
167 | 69 | addDirectory( resources, jos, parent ); |
168 | |
} |
169 | |
} |
170 | |
|
171 | |
|
172 | 150 | JarEntry entry = new JarEntry( name + "/" ); |
173 | 150 | jos.putNextEntry( entry ); |
174 | |
|
175 | 150 | resources.add( name ); |
176 | 150 | } |
177 | |
|
178 | |
private void addRemappedClass( RelocatorRemapper remapper, JarOutputStream jos, File jar, String name, |
179 | |
InputStream is ) |
180 | |
throws IOException |
181 | |
{ |
182 | 422 | if ( !remapper.hasRelocators() ) |
183 | |
{ |
184 | |
try |
185 | |
{ |
186 | 0 | jos.putNextEntry( new JarEntry( name ) ); |
187 | 0 | IOUtil.copy( is, jos ); |
188 | |
} |
189 | 0 | catch ( ZipException e ) |
190 | |
{ |
191 | 0 | getLogger().warn( "We have a duplicate " + name + " in " + jar ); |
192 | 0 | } |
193 | |
|
194 | 0 | return; |
195 | |
} |
196 | |
|
197 | 422 | ClassReader cr = new ClassReader( is ); |
198 | |
|
199 | 422 | ClassWriter cw = new ClassWriter( cr, 0 ); |
200 | |
|
201 | 422 | ClassVisitor cv = new RemappingClassAdapter( cw, remapper ); |
202 | |
|
203 | 422 | cr.accept( cv, ClassReader.EXPAND_FRAMES ); |
204 | |
|
205 | 422 | byte[] renamedClass = cw.toByteArray(); |
206 | |
|
207 | |
|
208 | 422 | String mappedName = remapper.map( name.substring( 0, name.indexOf( '.' ) ) ); |
209 | |
|
210 | |
try |
211 | |
{ |
212 | |
|
213 | 422 | jos.putNextEntry( new JarEntry( mappedName + ".class" ) ); |
214 | |
|
215 | 422 | IOUtil.copy( renamedClass, jos ); |
216 | |
} |
217 | 0 | catch ( ZipException e ) |
218 | |
{ |
219 | 0 | getLogger().warn( "We have a duplicate " + mappedName + " in " + jar ); |
220 | 422 | } |
221 | 422 | } |
222 | |
|
223 | |
private boolean isFiltered( List filters, String name ) |
224 | |
{ |
225 | 483 | for ( int i = 0; i < filters.size(); i++ ) |
226 | |
{ |
227 | 0 | Filter filter = (Filter) filters.get( i ); |
228 | |
|
229 | 0 | if ( filter.isFiltered( name ) ) |
230 | |
{ |
231 | 0 | return true; |
232 | |
} |
233 | |
} |
234 | |
|
235 | 483 | return false; |
236 | |
} |
237 | |
|
238 | |
private boolean resourceTransformed( List resourceTransformers, String name, InputStream is ) |
239 | |
throws IOException |
240 | |
{ |
241 | 61 | boolean resourceTransformed = false; |
242 | |
|
243 | 61 | for ( Iterator k = resourceTransformers.iterator(); k.hasNext(); ) |
244 | |
{ |
245 | 55 | ResourceTransformer transformer = (ResourceTransformer) k.next(); |
246 | |
|
247 | 55 | if ( transformer.canTransformResource( name ) ) |
248 | |
{ |
249 | 5 | transformer.processResource( is ); |
250 | |
|
251 | 5 | resourceTransformed = true; |
252 | |
|
253 | 5 | break; |
254 | |
} |
255 | |
} |
256 | 61 | return resourceTransformed; |
257 | |
} |
258 | |
|
259 | |
private void addResource( Set resources, JarOutputStream jos, String name, InputStream is ) |
260 | |
throws IOException |
261 | |
{ |
262 | 51 | jos.putNextEntry( new JarEntry( name ) ); |
263 | |
|
264 | 51 | IOUtil.copy( is, jos ); |
265 | |
|
266 | 51 | resources.add( name ); |
267 | 51 | } |
268 | |
|
269 | 7 | class RelocatorRemapper |
270 | |
extends Remapper |
271 | |
{ |
272 | |
List relocators; |
273 | |
|
274 | |
public RelocatorRemapper( List relocators ) |
275 | 7 | { |
276 | 7 | this.relocators = relocators; |
277 | 7 | } |
278 | |
|
279 | |
public boolean hasRelocators() |
280 | |
{ |
281 | 422 | return !relocators.isEmpty(); |
282 | |
} |
283 | |
|
284 | |
public Object mapValue( Object object ) |
285 | |
{ |
286 | 8212 | if ( object instanceof String ) |
287 | |
{ |
288 | 4603 | String name = (String) object; |
289 | 4603 | String value = name; |
290 | 4603 | for ( Iterator i = relocators.iterator(); i.hasNext(); ) |
291 | |
{ |
292 | 4603 | Relocator r = (Relocator) i.next(); |
293 | |
|
294 | 4603 | if ( r.canRelocatePath( name ) ) |
295 | |
{ |
296 | 0 | value = r.relocatePath( name ); |
297 | 0 | break; |
298 | |
} |
299 | |
|
300 | 4603 | if ( r.canRelocateClass( name ) ) |
301 | |
{ |
302 | 1 | value = r.relocateClass( name ); |
303 | 1 | break; |
304 | |
} |
305 | 4602 | if ( name.length() > 0 && name.charAt( 0 ) == '[' ) |
306 | |
{ |
307 | 0 | int count = 0; |
308 | 0 | while ( name.length() > 0 && name.charAt(0) == '[' ) |
309 | |
{ |
310 | 0 | name = name.substring( 1 ); |
311 | 0 | ++count; |
312 | |
} |
313 | |
|
314 | 0 | if ( name.length() > 0 |
315 | |
&& name.charAt( 0 ) == 'L' |
316 | |
&& name.charAt( name.length() - 1 ) == ';' ) |
317 | |
{ |
318 | 0 | name = name.substring( 1, name.length() - 1 ); |
319 | |
|
320 | 0 | if ( r.canRelocatePath( name ) ) |
321 | |
{ |
322 | 0 | value = 'L' + r.relocatePath( name ) + ';'; |
323 | 0 | while ( count > 0 ) |
324 | |
{ |
325 | 0 | value = '[' + value; |
326 | 0 | --count; |
327 | |
} |
328 | |
break; |
329 | |
} |
330 | |
|
331 | 0 | if ( r.canRelocateClass( name ) ) |
332 | |
{ |
333 | 0 | value = 'L' + r.relocateClass( name ) + ';'; |
334 | 0 | while (count > 0) |
335 | |
{ |
336 | 0 | value = '[' + value; |
337 | 0 | --count; |
338 | |
} |
339 | 4602 | break; |
340 | |
} |
341 | |
|
342 | |
} |
343 | |
} |
344 | |
} |
345 | |
|
346 | 4603 | return value; |
347 | |
} |
348 | |
else |
349 | |
{ |
350 | 3609 | object = super.mapValue( object ); |
351 | |
} |
352 | 3609 | return object; |
353 | |
} |
354 | |
|
355 | |
public String map( String name ) |
356 | |
{ |
357 | 102041 | String value = name; |
358 | 102041 | for ( Iterator i = relocators.iterator(); i.hasNext(); ) |
359 | |
{ |
360 | 102041 | Relocator r = (Relocator) i.next(); |
361 | |
|
362 | 102041 | if ( r.canRelocatePath( name ) ) |
363 | |
{ |
364 | 20977 | value = r.relocatePath( name ); |
365 | 20977 | break; |
366 | |
} |
367 | |
} |
368 | |
|
369 | 102041 | return value; |
370 | |
} |
371 | |
} |
372 | |
} |