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