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.ResourceTransformer;
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 ResourceTransformer
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 void processResource( final String resource, final InputStream is, final List<Relocator> relocators,
78 long time )
79 throws IOException
80 {
81 final Properties p = new Properties();
82 p.load( is );
83 properties.add( p );
84 if ( time > this.time )
85 {
86 this.time = time;
87 }
88 }
89
90 @Override
91 public boolean hasTransformedResource()
92 {
93 return !properties.isEmpty();
94 }
95
96 @Override
97 public void modifyOutputStream( JarOutputStream os )
98 throws IOException
99 {
100 if ( properties.isEmpty() )
101 {
102 return;
103 }
104
105 final Properties out = mergeProperties( sortProperties() );
106 if ( ordinalKey != null )
107 {
108 out.remove( ordinalKey );
109 }
110 if ( alreadyMergedKey != null )
111 {
112 out.remove( alreadyMergedKey );
113 }
114 JarEntry jarEntry = new JarEntry( resource );
115 jarEntry.setTime( time );
116 os.putNextEntry( jarEntry );
117 final BufferedWriter writer = new SkipPropertiesDateLineWriter(
118 new OutputStreamWriter( new NoCloseOutputStream( os ), StandardCharsets.ISO_8859_1 ) );
119 out.store( writer, " Merged by maven-shade-plugin (" + getClass().getName() + ")" );
120 writer.close();
121 os.closeEntry();
122 }
123
124 public void setReverseOrder( final boolean reverseOrder )
125 {
126 this.reverseOrder = reverseOrder;
127 }
128
129 public void setResource( final String resource )
130 {
131 this.resource = resource;
132 }
133
134 public void setOrdinalKey( final String ordinalKey )
135 {
136 this.ordinalKey = ordinalKey;
137 }
138
139 public void setDefaultOrdinal( final int defaultOrdinal )
140 {
141 this.defaultOrdinal = defaultOrdinal;
142 }
143
144 public void setAlreadyMergedKey( final String alreadyMergedKey )
145 {
146 this.alreadyMergedKey = alreadyMergedKey;
147 }
148
149 private List<Properties> sortProperties()
150 {
151 final List<Properties> sortedProperties = new ArrayList<>();
152 boolean foundMaster = false;
153 for ( final Properties current : properties )
154 {
155 if ( alreadyMergedKey != null )
156 {
157 final String master = current.getProperty( alreadyMergedKey );
158 if ( Boolean.parseBoolean( master ) )
159 {
160 if ( foundMaster )
161 {
162 throw new IllegalStateException(
163 "Ambiguous merged values: " + sortedProperties + ", " + current );
164 }
165 foundMaster = true;
166 sortedProperties.clear();
167 sortedProperties.add( current );
168 }
169 }
170 if ( !foundMaster )
171 {
172 final int configOrder = getConfigurationOrdinal( current );
173
174 int i;
175 for ( i = 0; i < sortedProperties.size(); i++ )
176 {
177 int listConfigOrder = getConfigurationOrdinal( sortedProperties.get( i ) );
178 if ( ( !reverseOrder && listConfigOrder > configOrder )
179 || ( reverseOrder && listConfigOrder < configOrder ) )
180 {
181 break;
182 }
183 }
184 sortedProperties.add( i, current );
185 }
186 }
187 return sortedProperties;
188 }
189
190 private int getConfigurationOrdinal( final Properties p )
191 {
192 if ( ordinalKey == null )
193 {
194 return defaultOrdinal;
195 }
196 final String configOrderString = p.getProperty( ordinalKey );
197 if ( configOrderString != null && configOrderString.length() > 0 )
198 {
199 return Integer.parseInt( configOrderString );
200 }
201 return defaultOrdinal;
202 }
203
204 private static Properties mergeProperties( final List<Properties> sortedProperties )
205 {
206 final Properties mergedProperties = new SortedProperties();
207 for ( final Properties p : sortedProperties )
208 {
209 mergedProperties.putAll( p );
210 }
211 return mergedProperties;
212 }
213 }