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