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