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