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 org.apache.maven.plugins.shade.relocation.Relocator;
23  import org.codehaus.plexus.util.StringUtils;
24  
25  import java.io.BufferedReader;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.InputStreamReader;
29  import java.io.OutputStreamWriter;
30  import java.io.PrintWriter;
31  import java.io.Writer;
32  import java.text.SimpleDateFormat;
33  import java.util.Date;
34  import java.util.Iterator;
35  import java.util.LinkedHashMap;
36  import java.util.LinkedHashSet;
37  import java.util.List;
38  import java.util.Map;
39  import java.util.Set;
40  import java.util.TreeSet;
41  import java.util.jar.JarEntry;
42  import java.util.jar.JarOutputStream;
43  
44  /**
45   * Merges <code>META-INF/NOTICE.TXT</code> files.
46   */
47  public class ApacheNoticeResourceTransformer
48      implements ResourceTransformer
49  {
50      Set<String> entries = new LinkedHashSet<String>();
51  
52      Map organizationEntries = new LinkedHashMap();
53  
54      String projectName = ""; // MSHADE-101 :: NullPointerException when projectName is missing
55  
56      boolean addHeader = true;
57  
58      String preamble1 = "// ------------------------------------------------------------------\n"
59          + "// NOTICE file corresponding to the section 4d of The Apache License,\n"
60          + "// Version 2.0, in this case for ";
61  
62      String preamble2 = "\n// ------------------------------------------------------------------\n";
63  
64      String preamble3 = "This product includes software developed at\n";
65  
66      //defaults overridable via config in pom
67      String organizationName = "The Apache Software Foundation";
68  
69      String organizationURL = "http://www.apache.org/";
70  
71      String inceptionYear = "2006";
72  
73      String copyright;
74  
75      /**
76       * The file encoding of the <code>NOTICE</code> file.
77       */
78      String encoding;
79  
80      private static final String NOTICE_PATH = "META-INF/NOTICE";
81  
82      private static final String NOTICE_TXT_PATH = "META-INF/NOTICE.txt";
83  
84      public boolean canTransformResource( String resource )
85      {
86          if ( NOTICE_PATH.equalsIgnoreCase( resource ) || NOTICE_TXT_PATH.equalsIgnoreCase( resource ) )
87          {
88              return true;
89          }
90  
91          return false;
92      }
93  
94      public void processResource( String resource, InputStream is, List<Relocator> relocators )
95          throws IOException
96      {
97          if ( entries.isEmpty() )
98          {
99              String year = new SimpleDateFormat( "yyyy" ).format( new Date() );
100             if ( !inceptionYear.equals( year ) )
101             {
102                 year = inceptionYear + "-" + year;
103             }
104 
105             //add headers
106             if ( addHeader )
107             {
108                 entries.add( preamble1 + projectName + preamble2 );
109             }
110             else
111             {
112                 entries.add( "" );
113             }
114             //fake second entry, we'll look for a real one later
115             entries.add( projectName + "\nCopyright " + year + " " + organizationName + "\n" );
116             entries.add( preamble3 + organizationName + " (" + organizationURL + ").\n" );
117         }
118 
119         BufferedReader reader;
120         if ( StringUtils.isNotEmpty( encoding ) )
121         {
122             reader = new BufferedReader( new InputStreamReader( is, encoding ) );
123         }
124         else
125         {
126             reader = new BufferedReader( new InputStreamReader( is ) );
127         }
128 
129         String line = reader.readLine();
130         StringBuffer sb = new StringBuffer();
131         Set currentOrg = null;
132         int lineCount = 0;
133         while ( line != null )
134         {
135             String trimedLine = line.trim();
136 
137             if ( !trimedLine.startsWith( "//" ) )
138             {
139                 if ( trimedLine.length() > 0 )
140                 {
141                     if ( trimedLine.startsWith( "- " ) )
142                     {
143                         //resource-bundle 1.3 mode
144                         if ( lineCount == 1
145                             && sb.toString().indexOf( "This product includes/uses software(s) developed by" ) != -1 )
146                         {
147                             currentOrg = (Set) organizationEntries.get( sb.toString().trim() );
148                             if ( currentOrg == null )
149                             {
150                                 currentOrg = new TreeSet();
151                                 organizationEntries.put( sb.toString().trim(), currentOrg );
152                             }
153                             sb = new StringBuffer();
154                         }
155                         else if ( sb.length() > 0 && currentOrg != null )
156                         {
157                             currentOrg.add( sb.toString() );
158                             sb = new StringBuffer();
159                         }
160 
161                     }
162                     sb.append( line ).append( "\n" );
163                     lineCount++;
164                 }
165                 else
166                 {
167                     String ent = sb.toString();
168                     if ( ent.startsWith( projectName ) && ent.indexOf( "Copyright " ) != -1 )
169                     {
170                         copyright = ent;
171                     }
172                     if ( currentOrg == null )
173                     {
174                         entries.add( ent );
175                     }
176                     else
177                     {
178                         currentOrg.add( ent );
179                     }
180                     sb = new StringBuffer();
181                     lineCount = 0;
182                     currentOrg = null;
183                 }
184             }
185 
186             line = reader.readLine();
187         }
188         if ( sb.length() > 0 )
189         {
190             if ( currentOrg == null )
191             {
192                 entries.add( sb.toString() );
193             }
194             else
195             {
196                 currentOrg.add( sb.toString() );
197             }
198         }
199     }
200 
201     public boolean hasTransformedResource()
202     {
203         return true;
204     }
205 
206     public void modifyOutputStream( JarOutputStream jos )
207         throws IOException
208     {
209         jos.putNextEntry( new JarEntry( NOTICE_PATH ) );
210 
211         Writer pow;
212         if ( StringUtils.isNotEmpty( encoding ) )
213         {
214             pow = new OutputStreamWriter( jos, encoding );
215         }
216         else
217         {
218             pow = new OutputStreamWriter( jos );
219         }
220         PrintWriter writer = new PrintWriter( pow );
221 
222         int count = 0;
223         for ( Iterator itr = entries.iterator(); itr.hasNext(); )
224         {
225             ++count;
226             String line = (String) itr.next();
227             if ( line.equals( copyright ) && count != 2 )
228             {
229                 continue;
230             }
231 
232             if ( count == 2 && copyright != null )
233             {
234                 writer.print( copyright );
235                 writer.print( '\n' );
236             }
237             else
238             {
239                 writer.print( line );
240                 writer.print( '\n' );
241             }
242             if ( count == 3 )
243             {
244                 //do org stuff
245                 for ( Iterator oit = organizationEntries.entrySet().iterator(); oit.hasNext(); )
246                 {
247                     Map.Entry entry = (Map.Entry) oit.next();
248                     writer.print( entry.getKey().toString() );
249                     writer.print( '\n' );
250                     Set entrySet = (Set) entry.getValue();
251                     for ( Iterator eit = entrySet.iterator(); eit.hasNext(); )
252                     {
253                         writer.print( eit.next().toString() );
254                     }
255                     writer.print( '\n' );
256                 }
257             }
258         }
259 
260         writer.flush();
261 
262         entries.clear();
263     }
264 }