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