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