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