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.properties;
20
21 import java.io.BufferedWriter;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStreamWriter;
25 import java.nio.charset.StandardCharsets;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.Objects;
29 import java.util.Properties;
30 import java.util.jar.JarEntry;
31 import java.util.jar.JarOutputStream;
32
33 import org.apache.maven.plugins.shade.relocation.Relocator;
34 import org.apache.maven.plugins.shade.resource.ReproducibleResourceTransformer;
35 import org.apache.maven.plugins.shade.resource.properties.io.NoCloseOutputStream;
36 import org.apache.maven.plugins.shade.resource.properties.io.SkipPropertiesDateLineWriter;
37
38
39
40
41
42
43 public class PropertiesTransformer implements ReproducibleResourceTransformer {
44 private String resource;
45 private String alreadyMergedKey;
46 private String ordinalKey;
47 private int defaultOrdinal;
48 private boolean reverseOrder;
49 private long time = Long.MIN_VALUE;
50
51 private final List<Properties> properties = new ArrayList<>();
52
53 public PropertiesTransformer() {
54
55 }
56
57 protected PropertiesTransformer(
58 final String resource, final String ordinalKey, final int defaultOrdinal, final boolean reversed) {
59 this.resource = resource;
60 this.ordinalKey = ordinalKey;
61 this.defaultOrdinal = defaultOrdinal;
62 this.reverseOrder = reversed;
63 }
64
65 @Override
66 public boolean canTransformResource(final String resource) {
67 return Objects.equals(resource, this.resource);
68 }
69
70 @Override
71 public final void processResource(String resource, InputStream is, List<Relocator> relocators) throws IOException {
72 processResource(resource, is, relocators, 0);
73 }
74
75 @Override
76 public void processResource(
77 final String resource, final InputStream is, final List<Relocator> relocators, long time)
78 throws IOException {
79 final Properties p = new Properties();
80 p.load(is);
81 properties.add(p);
82 if (time > this.time) {
83 this.time = time;
84 }
85 }
86
87 @Override
88 public boolean hasTransformedResource() {
89 return !properties.isEmpty();
90 }
91
92 @Override
93 public void modifyOutputStream(JarOutputStream os) throws IOException {
94 if (properties.isEmpty()) {
95 return;
96 }
97
98 final Properties out = mergeProperties(sortProperties());
99 if (ordinalKey != null) {
100 out.remove(ordinalKey);
101 }
102 if (alreadyMergedKey != null) {
103 out.remove(alreadyMergedKey);
104 }
105 JarEntry jarEntry = new JarEntry(resource);
106 jarEntry.setTime(time);
107 os.putNextEntry(jarEntry);
108 final BufferedWriter writer = new SkipPropertiesDateLineWriter(
109 new OutputStreamWriter(new NoCloseOutputStream(os), StandardCharsets.ISO_8859_1));
110 out.store(writer, " Merged by maven-shade-plugin (" + getClass().getName() + ")");
111 writer.close();
112 os.closeEntry();
113 }
114
115 public void setReverseOrder(final boolean reverseOrder) {
116 this.reverseOrder = reverseOrder;
117 }
118
119 public void setResource(final String resource) {
120 this.resource = resource;
121 }
122
123 public void setOrdinalKey(final String ordinalKey) {
124 this.ordinalKey = ordinalKey;
125 }
126
127 public void setDefaultOrdinal(final int defaultOrdinal) {
128 this.defaultOrdinal = defaultOrdinal;
129 }
130
131 public void setAlreadyMergedKey(final String alreadyMergedKey) {
132 this.alreadyMergedKey = alreadyMergedKey;
133 }
134
135 private List<Properties> sortProperties() {
136 final List<Properties> sortedProperties = new ArrayList<>();
137 boolean foundMaster = false;
138 for (final Properties current : properties) {
139 if (alreadyMergedKey != null) {
140 final String master = current.getProperty(alreadyMergedKey);
141 if (Boolean.parseBoolean(master)) {
142 if (foundMaster) {
143 throw new IllegalStateException(
144 "Ambiguous merged values: " + sortedProperties + ", " + current);
145 }
146 foundMaster = true;
147 sortedProperties.clear();
148 sortedProperties.add(current);
149 }
150 }
151 if (!foundMaster) {
152 final int configOrder = getConfigurationOrdinal(current);
153
154 int i;
155 for (i = 0; i < sortedProperties.size(); i++) {
156 int listConfigOrder = getConfigurationOrdinal(sortedProperties.get(i));
157 if ((!reverseOrder && listConfigOrder > configOrder)
158 || (reverseOrder && listConfigOrder < configOrder)) {
159 break;
160 }
161 }
162 sortedProperties.add(i, current);
163 }
164 }
165 return sortedProperties;
166 }
167
168 private int getConfigurationOrdinal(final Properties p) {
169 if (ordinalKey == null) {
170 return defaultOrdinal;
171 }
172 final String configOrderString = p.getProperty(ordinalKey);
173 if (configOrderString != null && configOrderString.length() > 0) {
174 return Integer.parseInt(configOrderString);
175 }
176 return defaultOrdinal;
177 }
178
179 private static Properties mergeProperties(final List<Properties> sortedProperties) {
180 final Properties mergedProperties = new SortedProperties();
181 for (final Properties p : sortedProperties) {
182 mergedProperties.putAll(p);
183 }
184 return mergedProperties;
185 }
186 }