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