1 package org.apache.maven.plugins.shade.resource;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.nio.charset.StandardCharsets;
25 import java.util.HashMap;
26 import java.util.LinkedHashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Scanner;
30 import java.util.Set;
31 import java.util.jar.JarEntry;
32 import java.util.jar.JarOutputStream;
33
34 import org.apache.commons.io.IOUtils;
35 import org.apache.maven.plugins.shade.relocation.Relocator;
36
37
38
39
40
41
42
43
44 public class ServicesResourceTransformer
45 extends AbstractCompatibilityTransformer
46 {
47 private static final String SERVICES_PATH = "META-INF/services";
48
49 private final Map<String, Set<String>> serviceEntries = new HashMap<>();
50
51 private long time = Long.MIN_VALUE;
52
53 public boolean canTransformResource( String resource )
54 {
55 return resource.startsWith( SERVICES_PATH );
56 }
57
58 public void processResource( String resource, InputStream is, final List<Relocator> relocators, long time )
59 throws IOException
60 {
61 resource = resource.substring( SERVICES_PATH.length() + 1 );
62 for ( Relocator relocator : relocators )
63 {
64 if ( relocator.canRelocateClass( resource ) )
65 {
66 resource = relocator.relocateClass( resource );
67 break;
68 }
69 }
70 resource = SERVICES_PATH + '/' + resource;
71
72 Set<String> out = serviceEntries.computeIfAbsent( resource, k -> new LinkedHashSet<>() );
73
74 Scanner scanner = new Scanner( is, StandardCharsets.UTF_8.name() );
75 while ( scanner.hasNextLine() )
76 {
77 String relContent = scanner.nextLine();
78 for ( Relocator relocator : relocators )
79 {
80 if ( relocator.canRelocateClass( relContent ) )
81 {
82 relContent = relocator.applyToSourceContent( relContent );
83 }
84 }
85 out.add( relContent );
86 }
87
88 if ( time > this.time )
89 {
90 this.time = time;
91 }
92 }
93
94 public boolean hasTransformedResource()
95 {
96 return !serviceEntries.isEmpty();
97 }
98
99 public void modifyOutputStream( JarOutputStream jos )
100 throws IOException
101 {
102 for ( Map.Entry<String, Set<String>> entry : serviceEntries.entrySet() )
103 {
104 String key = entry.getKey();
105 Set<String> data = entry.getValue();
106
107 JarEntry jarEntry = new JarEntry( key );
108 jarEntry.setTime( time );
109 jos.putNextEntry( jarEntry );
110
111 IOUtils.writeLines( data, "\n", jos, StandardCharsets.UTF_8 );
112 jos.flush();
113 data.clear();
114 }
115 }
116 }