View Javadoc

1   package org.apache.maven.plugins.shade.resource;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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.LinkedList;
29  import java.util.List;
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.IOUtil;
35  import org.codehaus.plexus.util.ReaderFactory;
36  import org.codehaus.plexus.util.WriterFactory;
37  import org.codehaus.plexus.util.xml.Xpp3Dom;
38  import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
39  import org.codehaus.plexus.util.xml.Xpp3DomWriter;
40  
41  /**
42   * A resource processor that aggregates Maven <code>plugin.xml</code> files.
43   * 
44   * @author Robert Scholte
45   * @since 3.0
46   */
47  public class PluginXmlResourceTransformer
48      implements ResourceTransformer
49  {
50      private List<Xpp3Dom> mojos = new LinkedList<Xpp3Dom>();
51  
52      public static final String PLUGIN_XML_PATH = "META-INF/maven/plugin.xml";
53  
54      public boolean canTransformResource( String resource )
55      {
56          return PLUGIN_XML_PATH.equals( resource );
57      }
58  
59      public void processResource( String resource, InputStream is, List<Relocator> 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                      // leave ZIP open
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 plugin.xml in " + is ).initCause( e );
82          }
83  
84          // Only try to merge in mojos if there are some elements in the plugin
85          if ( newDom.getChild( "mojos" ) == null )
86          {
87              return;
88          }
89  
90          for ( Xpp3Dom mojo : newDom.getChild( "mojos" ).getChildren( "mojo" ) )
91          {
92  
93              String impl = getValue( mojo, "implementation" );
94              impl = getRelocatedClass( impl, relocators );
95              setValue( mojo, "implementation", impl );
96  
97              Xpp3Dom parameters = mojo.getChild( "parameters" );
98              if ( parameters != null )
99              {
100                 for ( Xpp3Dom parameter : parameters.getChildren() )
101                 {
102                     String type = getValue( parameter, "type" );
103                     type = getRelocatedClass( type, relocators );
104                     setValue( parameter, "type", type );
105                 }
106             }
107 
108             Xpp3Dom configuration = mojo.getChild( "configuration" );
109             if ( configuration != null )
110             {
111                 for ( Xpp3Dom configurationEntry : configuration.getChildren() )
112                 {
113                     String implementation = getAttribute( configurationEntry, "implementation" );
114                     implementation = getRelocatedClass( implementation, relocators );
115                     setAttribute( configurationEntry, "implementation", implementation );
116                 }
117             }
118 
119             Xpp3Dom requirements = mojo.getChild( "requirements" );
120             if ( requirements != null && requirements.getChildCount() > 0 )
121             {
122                 for ( Xpp3Dom requirement : requirements.getChildren() )
123                 {
124                     String requiredRole = getValue( requirement, "role" );
125                     requiredRole = getRelocatedClass( requiredRole, relocators );
126                     setValue( requirement, "role", requiredRole );
127                 }
128             }
129             mojos.add( mojo );
130         }
131     }
132 
133     public void modifyOutputStream( JarOutputStream jos )
134         throws IOException
135     {
136         byte[] data = getTransformedResource();
137 
138         jos.putNextEntry( new JarEntry( PLUGIN_XML_PATH ) );
139 
140         IOUtil.copy( data, jos );
141 
142         mojos.clear();
143     }
144 
145     public boolean hasTransformedResource()
146     {
147         return !mojos.isEmpty();
148     }
149 
150     byte[] getTransformedResource()
151         throws IOException
152     {
153         ByteArrayOutputStream baos = new ByteArrayOutputStream( 1024 * 4 );
154 
155         Writer writer = WriterFactory.newXmlWriter( baos );
156         try
157         {
158             Xpp3Dom dom = new Xpp3Dom( "plugin" );
159 
160             Xpp3Dom componentDom = new Xpp3Dom( "mojos" );
161 
162             dom.addChild( componentDom );
163 
164             for ( Xpp3Dom mojo : mojos )
165             {
166                 componentDom.addChild( mojo );
167             }
168 
169             Xpp3DomWriter.write( writer, dom );
170         }
171         finally
172         {
173             IOUtil.close( writer );
174         }
175 
176         return baos.toByteArray();
177     }
178 
179     private String getRelocatedClass( String className, List<Relocator> relocators )
180     {
181         if ( className != null && className.length() > 0 && relocators != null )
182         {
183             for ( Relocator relocator : relocators )
184             {
185                 if ( relocator.canRelocateClass( className ) )
186                 {
187                     return relocator.relocateClass( className );
188                 }
189             }
190         }
191 
192         return className;
193     }
194 
195     private static String getValue( Xpp3Dom dom, String element )
196     {
197         Xpp3Dom child = dom.getChild( element );
198 
199         return ( child != null && child.getValue() != null ) ? child.getValue() : "";
200     }
201 
202     private static void setValue( Xpp3Dom dom, String element, String value )
203     {
204         Xpp3Dom child = dom.getChild( element );
205 
206         if ( child == null || value == null || value.length() <= 0 )
207         {
208             return;
209         }
210 
211         child.setValue( value );
212     }
213 
214     private static String getAttribute( Xpp3Dom dom, String attribute )
215     {
216         return ( dom.getAttribute( attribute ) != null ) ? dom.getAttribute( attribute ) : "";
217     }
218 
219     private static void setAttribute( Xpp3Dom dom, String attribute, String value )
220     {
221         String attr = dom.getAttribute( attribute );
222 
223         if ( attr == null || value == null || value.length() <= 0 )
224         {
225             return;
226         }
227 
228         dom.setAttribute( attribute, value );
229     }
230 
231 }