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.ArrayList;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Scanner;
30 import java.util.jar.JarEntry;
31 import java.util.jar.JarOutputStream;
32
33 import org.apache.commons.io.IOUtils;
34 import org.apache.maven.plugins.shade.relocation.Relocator;
35
36
37
38
39
40
41
42
43 public class ServicesResourceTransformer
44 extends AbstractCompatibilityTransformer
45 {
46
47 private static final String SERVICES_PATH = "META-INF/services";
48
49 private final Map<String, ArrayList<String>> serviceEntries = new HashMap<>();
50
51 private List<Relocator> relocators;
52
53 private long time = Long.MIN_VALUE;
54
55 public boolean canTransformResource( String resource )
56 {
57 return resource.startsWith( SERVICES_PATH );
58 }
59
60 public void processResource( String resource, InputStream is, final List<Relocator> relocators, long time )
61 throws IOException
62 {
63 ArrayList<String> out = serviceEntries.get( resource );
64 if ( out == null )
65 {
66 out = new ArrayList<>();
67 serviceEntries.put( resource, out );
68 }
69
70 Scanner scanner = new Scanner( is, StandardCharsets.UTF_8.name() );
71 while ( scanner.hasNextLine() )
72 {
73 String relContent = scanner.nextLine();
74 for ( Relocator relocator : relocators )
75 {
76 if ( relocator.canRelocateClass( relContent ) )
77 {
78 relContent = relocator.applyToSourceContent( relContent );
79 }
80 }
81 out.add( relContent );
82 }
83
84 if ( this.relocators == null )
85 {
86 this.relocators = relocators;
87 }
88
89 if ( time > this.time )
90 {
91 this.time = time;
92 }
93 }
94
95 public boolean hasTransformedResource()
96 {
97 return !serviceEntries.isEmpty();
98 }
99
100 public void modifyOutputStream( JarOutputStream jos )
101 throws IOException
102 {
103 for ( Map.Entry<String, ArrayList<String>> entry : serviceEntries.entrySet() )
104 {
105 String key = entry.getKey();
106 ArrayList<String> data = entry.getValue();
107
108 if ( relocators != null )
109 {
110 key = key.substring( SERVICES_PATH.length() + 1 );
111 for ( Relocator relocator : relocators )
112 {
113 if ( relocator.canRelocateClass( key ) )
114 {
115 key = relocator.relocateClass( key );
116 break;
117 }
118 }
119
120 key = SERVICES_PATH + '/' + key;
121 }
122
123 JarEntry jarEntry = new JarEntry( key );
124 jarEntry.setTime( time );
125 jos.putNextEntry( jarEntry );
126
127 IOUtils.writeLines( data, "\n", jos, StandardCharsets.UTF_8 );
128 jos.flush();
129 data.clear();
130 }
131 }
132 }