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<String>();
50
51 Map<String, Set<String>> organizationEntries = new LinkedHashMap<String, Set<String>>();
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 static final String NOTICE_PATH = "META-INF/NOTICE";
80
81 private static final String NOTICE_TXT_PATH = "META-INF/NOTICE.txt";
82
83 public boolean canTransformResource( String resource )
84 {
85 return NOTICE_PATH.equalsIgnoreCase( resource ) || NOTICE_TXT_PATH.equalsIgnoreCase( resource );
86
87 }
88
89 public void processResource( String resource, InputStream is, List<Relocator> relocators )
90 throws IOException
91 {
92 if ( entries.isEmpty() )
93 {
94 String year = new SimpleDateFormat( "yyyy" ).format( new Date() );
95 if ( !inceptionYear.equals( year ) )
96 {
97 year = inceptionYear + "-" + year;
98 }
99
100
101 if ( addHeader )
102 {
103 entries.add( preamble1 + projectName + preamble2 );
104 }
105 else
106 {
107 entries.add( "" );
108 }
109
110 entries.add( projectName + "\nCopyright " + year + " " + organizationName + "\n" );
111 entries.add( preamble3 + organizationName + " (" + organizationURL + ").\n" );
112 }
113
114 BufferedReader reader;
115 if ( StringUtils.isNotEmpty( encoding ) )
116 {
117 reader = new BufferedReader( new InputStreamReader( is, encoding ) );
118 }
119 else
120 {
121 reader = new BufferedReader( new InputStreamReader( is ) );
122 }
123
124 String line = reader.readLine();
125 StringBuilder sb = new StringBuilder();
126 Set<String> currentOrg = null;
127 int lineCount = 0;
128 while ( line != null )
129 {
130 String trimedLine = line.trim();
131
132 if ( !trimedLine.startsWith( "//" ) )
133 {
134 if ( trimedLine.length() > 0 )
135 {
136 if ( trimedLine.startsWith( "- " ) )
137 {
138
139 if ( lineCount == 1
140 && sb.toString().contains( "This product includes/uses software(s) developed by" ) )
141 {
142 currentOrg = organizationEntries.get( sb.toString().trim() );
143 if ( currentOrg == null )
144 {
145 currentOrg = new TreeSet<String>();
146 organizationEntries.put( sb.toString().trim(), currentOrg );
147 }
148 sb = new StringBuilder();
149 }
150 else if ( sb.length() > 0 && currentOrg != null )
151 {
152 currentOrg.add( sb.toString() );
153 sb = new StringBuilder();
154 }
155
156 }
157 sb.append( line ).append( "\n" );
158 lineCount++;
159 }
160 else
161 {
162 String ent = sb.toString();
163 if ( ent.startsWith( projectName ) && ent.contains( "Copyright " ) )
164 {
165 copyright = ent;
166 }
167 if ( currentOrg == null )
168 {
169 entries.add( ent );
170 }
171 else
172 {
173 currentOrg.add( ent );
174 }
175 sb = new StringBuilder();
176 lineCount = 0;
177 currentOrg = null;
178 }
179 }
180
181 line = reader.readLine();
182 }
183 if ( sb.length() > 0 )
184 {
185 if ( currentOrg == null )
186 {
187 entries.add( sb.toString() );
188 }
189 else
190 {
191 currentOrg.add( sb.toString() );
192 }
193 }
194 }
195
196 public boolean hasTransformedResource()
197 {
198 return true;
199 }
200
201 public void modifyOutputStream( JarOutputStream jos )
202 throws IOException
203 {
204 jos.putNextEntry( new JarEntry( NOTICE_PATH ) );
205
206 Writer pow;
207 if ( StringUtils.isNotEmpty( encoding ) )
208 {
209 pow = new OutputStreamWriter( jos, encoding );
210 }
211 else
212 {
213 pow = new OutputStreamWriter( jos );
214 }
215 PrintWriter writer = new PrintWriter( pow );
216
217 int count = 0;
218 for ( String line : entries )
219 {
220 ++count;
221 if ( line.equals( copyright ) && count != 2 )
222 {
223 continue;
224 }
225
226 if ( count == 2 && copyright != null )
227 {
228 writer.print( copyright );
229 writer.print( '\n' );
230 }
231 else
232 {
233 writer.print( line );
234 writer.print( '\n' );
235 }
236 if ( count == 3 )
237 {
238
239 for ( Map.Entry<String, Set<String>> entry : organizationEntries.entrySet() )
240 {
241 writer.print( entry.getKey() );
242 writer.print( '\n' );
243 for ( String l : entry.getValue() )
244 {
245 writer.print( l );
246 }
247 writer.print( '\n' );
248 }
249 }
250 }
251
252 writer.flush();
253
254 entries.clear();
255 }
256 }