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.BufferedInputStream;
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.Reader;
26 import java.io.Writer;
27 import java.util.LinkedHashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.jar.JarEntry;
31 import java.util.jar.JarOutputStream;
32
33 import org.apache.maven.plugins.shade.relocation.Relocator;
34 import org.codehaus.plexus.util.ReaderFactory;
35 import org.codehaus.plexus.util.WriterFactory;
36 import org.codehaus.plexus.util.xml.Xpp3Dom;
37 import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
38 import org.codehaus.plexus.util.xml.Xpp3DomWriter;
39
40
41
42
43 public class ComponentsXmlResourceTransformer extends AbstractCompatibilityTransformer {
44 private Map<String, Xpp3Dom> components = new LinkedHashMap<>();
45
46 private long time = Long.MIN_VALUE;
47
48 public static final String COMPONENTS_XML_PATH = "META-INF/plexus/components.xml";
49
50 public boolean canTransformResource(String resource) {
51 return COMPONENTS_XML_PATH.equals(resource);
52 }
53
54 public void processResource(String resource, InputStream is, List<Relocator> relocators, long time)
55 throws IOException {
56 Xpp3Dom newDom;
57
58 try {
59 BufferedInputStream bis = new BufferedInputStream(is) {
60 public void close() throws IOException {
61
62 }
63 };
64
65 Reader reader = ReaderFactory.newXmlReader(bis);
66
67 newDom = Xpp3DomBuilder.build(reader);
68 } catch (Exception e) {
69 throw new IOException("Error parsing components.xml in " + is, e);
70 }
71
72
73 if (newDom.getChild("components") == null) {
74 return;
75 }
76
77 Xpp3Dom[] children = newDom.getChild("components").getChildren("component");
78
79 for (Xpp3Dom component : children) {
80 String role = getValue(component, "role");
81 role = getRelocatedClass(role, relocators);
82 setValue(component, "role", role);
83
84 String roleHint = getValue(component, "role-hint");
85
86 String impl = getValue(component, "implementation");
87 impl = getRelocatedClass(impl, relocators);
88 setValue(component, "implementation", impl);
89
90 String key = role + ':' + roleHint;
91 if (components.containsKey(key)) {
92
93
94
95 Xpp3Dom dom = components.get(key);
96 if (dom.getChild("configuration") != null) {
97 component.addChild(dom.getChild("configuration"));
98 }
99 }
100
101 Xpp3Dom requirements = component.getChild("requirements");
102 if (requirements != null && requirements.getChildCount() > 0) {
103 for (int r = requirements.getChildCount() - 1; r >= 0; r--) {
104 Xpp3Dom requirement = requirements.getChild(r);
105
106 String requiredRole = getValue(requirement, "role");
107 requiredRole = getRelocatedClass(requiredRole, relocators);
108 setValue(requirement, "role", requiredRole);
109 }
110 }
111
112 components.put(key, component);
113 }
114
115 if (time > this.time) {
116 this.time = time;
117 }
118 }
119
120 public void modifyOutputStream(JarOutputStream jos) throws IOException {
121 JarEntry jarEntry = new JarEntry(COMPONENTS_XML_PATH);
122 jarEntry.setTime(time);
123
124 byte[] data = getTransformedResource();
125
126 jos.putNextEntry(jarEntry);
127
128 jos.write(data);
129
130 components.clear();
131 }
132
133 public boolean hasTransformedResource() {
134 return !components.isEmpty();
135 }
136
137 byte[] getTransformedResource() throws IOException {
138 ByteArrayOutputStream baos = new ByteArrayOutputStream(1024 * 4);
139
140 try (Writer writer = WriterFactory.newXmlWriter(baos)) {
141 Xpp3Dom dom = new Xpp3Dom("component-set");
142
143 Xpp3Dom componentDom = new Xpp3Dom("components");
144
145 dom.addChild(componentDom);
146
147 for (Xpp3Dom component : components.values()) {
148 componentDom.addChild(component);
149 }
150
151 Xpp3DomWriter.write(writer, dom);
152 }
153
154 return baos.toByteArray();
155 }
156
157 private String getRelocatedClass(String className, List<Relocator> relocators) {
158 if (className != null && className.length() > 0 && relocators != null) {
159 for (Relocator relocator : relocators) {
160 if (relocator.canRelocateClass(className)) {
161 return relocator.relocateClass(className);
162 }
163 }
164 }
165
166 return className;
167 }
168
169 private static String getValue(Xpp3Dom dom, String element) {
170 Xpp3Dom child = dom.getChild(element);
171
172 return (child != null && child.getValue() != null) ? child.getValue() : "";
173 }
174
175 private static void setValue(Xpp3Dom dom, String element, String value) {
176 Xpp3Dom child = dom.getChild(element);
177
178 if (child == null || value == null || value.length() <= 0) {
179 return;
180 }
181
182 child.setValue(value);
183 }
184 }