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