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 java.io.IOException;
23 import java.io.InputStream;
24 import java.util.Arrays;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.jar.Attributes;
28 import java.util.jar.JarEntry;
29 import java.util.jar.JarFile;
30 import java.util.jar.JarOutputStream;
31 import java.util.jar.Manifest;
32
33 import org.apache.maven.plugins.shade.relocation.Relocator;
34
35
36
37
38
39
40
41
42
43 public class ManifestResourceTransformer
44 extends AbstractCompatibilityTransformer
45 {
46 private final List<String> defaultAttributes = Arrays.asList( "Export-Package",
47 "Import-Package",
48 "Provide-Capability",
49 "Require-Capability" );
50
51
52 private String mainClass;
53
54 private Map<String, Object> manifestEntries;
55
56 private List<String> additionalAttributes;
57
58
59 private boolean manifestDiscovered;
60
61 private Manifest manifest;
62
63 private long time = Long.MIN_VALUE;
64
65 private String shade;
66
67 public void setMainClass( String mainClass )
68 {
69 this.mainClass = mainClass;
70 }
71
72 public void setManifestEntries( Map<String, Object> manifestEntries )
73 {
74 this.manifestEntries = manifestEntries;
75 }
76
77 public void setAdditionalAttributes( List<String> additionalAttributes )
78 {
79 this.additionalAttributes = additionalAttributes;
80 }
81
82 @Override
83 public boolean canTransformResource( String resource )
84 {
85 return JarFile.MANIFEST_NAME.equalsIgnoreCase( resource );
86 }
87
88 @Override
89 public void processResource( String resource, InputStream is, List<Relocator> relocators, long time )
90 throws IOException
91 {
92
93
94
95 if ( !manifestDiscovered )
96 {
97 manifest = new Manifest( is );
98
99 if ( relocators != null && !relocators.isEmpty() )
100 {
101 final Attributes attributes = manifest.getMainAttributes();
102
103 for ( final String attribute : defaultAttributes )
104 {
105 final String attributeValue = attributes.getValue( attribute );
106 if ( attributeValue != null )
107 {
108 String newValue = relocate( attributeValue, relocators );
109 attributes.putValue( attribute, newValue );
110 }
111 }
112
113 if ( additionalAttributes != null )
114 {
115 for ( final String attribute : additionalAttributes )
116 {
117 final String attributeValue = attributes.getValue( attribute );
118 if ( attributeValue != null )
119 {
120 String newValue = relocate( attributeValue, relocators );
121 attributes.putValue( attribute, newValue );
122 }
123 }
124 }
125 }
126
127 manifestDiscovered = true;
128
129 if ( time > this.time )
130 {
131 this.time = time;
132 }
133 }
134 }
135
136 @Override
137 public boolean hasTransformedResource()
138 {
139 return true;
140 }
141
142 @Override
143 public void modifyOutputStream( JarOutputStream jos )
144 throws IOException
145 {
146
147 if ( manifest == null )
148 {
149 manifest = new Manifest();
150 }
151
152 Attributes attributes = manifest.getMainAttributes();
153
154 if ( mainClass != null )
155 {
156 attributes.put( Attributes.Name.MAIN_CLASS, mainClass );
157 }
158
159 if ( manifestEntries != null )
160 {
161 for ( Map.Entry<String, Object> entry : manifestEntries.entrySet() )
162 {
163 if ( entry.getValue() == null )
164 {
165 attributes.remove( new Attributes.Name( entry.getKey() ) );
166 }
167 else
168 {
169 attributes.put( new Attributes.Name( entry.getKey() ), entry.getValue() );
170 }
171 }
172 }
173
174 JarEntry jarEntry = new JarEntry( JarFile.MANIFEST_NAME );
175 jarEntry.setTime( time );
176 jos.putNextEntry( jarEntry );
177 manifest.write( jos );
178 }
179
180 private String relocate( String originalValue, List<Relocator> relocators )
181 {
182 String newValue = originalValue;
183 for ( Relocator relocator : relocators )
184 {
185 String value;
186 do
187 {
188 value = newValue;
189 newValue = relocator.relocateClass( value );
190 }
191 while ( !value.equals( newValue ) );
192 }
193 return newValue;
194 }
195
196
197
198
199
200
201 public void setForShade( String shade )
202 {
203 this.shade = shade;
204 }
205
206 public boolean isForShade( String shade )
207 {
208 return isUsedForDefaultShading() || this.shade.equalsIgnoreCase( shade );
209 }
210
211 public boolean isUsedForDefaultShading()
212 {
213 return this.shade == null || this.shade.isEmpty();
214 }
215 }