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