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