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