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 public boolean canTransformResource( String resource )
60 {
61 if ( resource.startsWith( SERVICES_PATH ) )
62 {
63 return true;
64 }
65
66 return false;
67 }
68
69 public void processResource( String resource, InputStream is, final List<Relocator> relocators )
70 throws IOException
71 {
72 ServiceStream out = serviceEntries.get( resource );
73 if ( out == null )
74 {
75 out = new ServiceStream();
76 serviceEntries.put( resource, out );
77 }
78
79 final ServiceStream fout = out;
80
81 final String content = IOUtils.toString( is );
82 StringReader reader = new StringReader( content );
83 LineReader lineReader = new LineReader( reader );
84 String line;
85 while ( ( line = lineReader.readLine() ) != null )
86 {
87 String relContent = line;
88 for ( Relocator relocator : relocators )
89 {
90 if ( relocator.canRelocateClass( relContent ) )
91 {
92 relContent = relocator.applyToSourceContent( relContent );
93 }
94 }
95 fout.append( relContent + "\n" );
96 }
97
98 if ( this.relocators == null )
99 {
100 this.relocators = relocators;
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 jos.putNextEntry( new JarEntry( key ) );
132
133
134
135 PrintWriter writer = new PrintWriter( jos );
136 InputStreamReader streamReader = new InputStreamReader( data.toInputStream() );
137 BufferedReader reader = new BufferedReader( streamReader );
138 String className;
139
140 while ( ( className = reader.readLine() ) != null )
141 {
142 writer.println( className );
143 writer.flush();
144 }
145
146 reader.close();
147 data.reset();
148 }
149 }
150
151 static class ServiceStream
152 extends ByteArrayOutputStream
153 {
154
155 ServiceStream()
156 {
157 super( 1024 );
158 }
159
160 public void append( String content )
161 throws IOException
162 {
163 if ( count > 0 && buf[count - 1] != '\n' && buf[count - 1] != '\r' )
164 {
165 write( '\n' );
166 }
167
168 byte[] contentBytes = content.getBytes( StandardCharsets.UTF_8 );
169 this.write( contentBytes );
170 }
171
172 public InputStream toInputStream()
173 {
174 return new ByteArrayInputStream( buf, 0, count );
175 }
176
177 }
178
179 }