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.BufferedReader;
23 import java.io.ByteArrayInputStream;
24 import java.io.ByteArrayOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.io.OutputStreamWriter;
29 import java.io.StringReader;
30 import java.io.Writer;
31 import java.nio.charset.StandardCharsets;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.jar.JarEntry;
36 import java.util.jar.JarOutputStream;
37
38 import org.apache.commons.io.IOUtils;
39 import org.apache.maven.plugins.shade.relocation.Relocator;
40
41
42
43
44
45
46
47
48 public class ServicesResourceTransformer
49 extends AbstractCompatibilityTransformer
50 {
51
52 private static final String SERVICES_PATH = "META-INF/services";
53
54 private Map<String, ServiceStream> serviceEntries = new HashMap<>();
55
56 private List<Relocator> relocators;
57
58 private long time = Long.MIN_VALUE;
59
60 public boolean canTransformResource( String resource )
61 {
62 return resource.startsWith( SERVICES_PATH );
63 }
64
65 public void processResource( String resource, InputStream is, final List<Relocator> relocators, long time )
66 throws IOException
67 {
68 ServiceStream out = serviceEntries.get( resource );
69 if ( out == null )
70 {
71 out = new ServiceStream();
72 serviceEntries.put( resource, out );
73 }
74
75 final String content = IOUtils.toString( is, StandardCharsets.UTF_8 );
76 StringReader reader = new StringReader( content );
77 BufferedReader lineReader = new BufferedReader( reader );
78 String line;
79 while ( ( line = lineReader.readLine() ) != null )
80 {
81 String relContent = line;
82 for ( Relocator relocator : relocators )
83 {
84 if ( relocator.canRelocateClass( relContent ) )
85 {
86 relContent = relocator.applyToSourceContent( relContent );
87 }
88 }
89 out.append( relContent + "\n" );
90 }
91
92 if ( this.relocators == null )
93 {
94 this.relocators = relocators;
95 }
96
97 if ( time > this.time )
98 {
99 this.time = time;
100 }
101 }
102
103 public boolean hasTransformedResource()
104 {
105 return serviceEntries.size() > 0;
106 }
107
108 public void modifyOutputStream( JarOutputStream jos )
109 throws IOException
110 {
111 for ( Map.Entry<String, ServiceStream> entry : serviceEntries.entrySet() )
112 {
113 String key = entry.getKey();
114 ServiceStream data = entry.getValue();
115
116 if ( relocators != null )
117 {
118 key = key.substring( SERVICES_PATH.length() + 1 );
119 for ( Relocator relocator : relocators )
120 {
121 if ( relocator.canRelocateClass( key ) )
122 {
123 key = relocator.relocateClass( key );
124 break;
125 }
126 }
127
128 key = SERVICES_PATH + '/' + key;
129 }
130
131 JarEntry jarEntry = new JarEntry( key );
132 jarEntry.setTime( time );
133 jos.putNextEntry( jarEntry );
134
135
136
137
138 Writer writer = new OutputStreamWriter( jos, StandardCharsets.UTF_8 );
139 InputStreamReader streamReader = new InputStreamReader( data.toInputStream() );
140 BufferedReader reader = new BufferedReader( streamReader );
141 String className;
142
143 while ( ( className = reader.readLine() ) != null )
144 {
145 writer.write( className );
146 writer.write( System.lineSeparator() );
147 writer.flush();
148 }
149
150 reader.close();
151 data.reset();
152 }
153 }
154
155 static class ServiceStream
156 extends ByteArrayOutputStream
157 {
158
159 ServiceStream()
160 {
161 super( 1024 );
162 }
163
164 public void append( String content )
165 throws IOException
166 {
167 if ( count > 0 && buf[count - 1] != '\n' && buf[count - 1] != '\r' )
168 {
169 write( '\n' );
170 }
171
172 byte[] contentBytes = content.getBytes( StandardCharsets.UTF_8 );
173 this.write( contentBytes );
174 }
175
176 public InputStream toInputStream()
177 {
178 return new ByteArrayInputStream( buf, 0, count );
179 }
180
181 }
182
183 }