View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.settings;
20  
21  import java.io.IOError;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  import java.io.PrintStream;
26  import java.io.PrintWriter;
27  import java.io.Reader;
28  import java.io.Writer;
29  import java.util.AbstractSet;
30  import java.util.Collection;
31  import java.util.Collections;
32  import java.util.Enumeration;
33  import java.util.InvalidPropertiesFormatException;
34  import java.util.Iterator;
35  import java.util.Map;
36  import java.util.Properties;
37  import java.util.Set;
38  import java.util.function.BiConsumer;
39  import java.util.function.BiFunction;
40  import java.util.function.Consumer;
41  import java.util.function.Function;
42  import java.util.function.Supplier;
43  
44  class WrapperProperties extends Properties {
45  
46      final Supplier<Map<String, String>> getter;
47      final Consumer<Properties> setter;
48  
49      WrapperProperties(Supplier<Map<String, String>> getter, Consumer<Properties> setter) {
50          this.getter = getter;
51          this.setter = setter;
52      }
53  
54      @Override
55      public String getProperty(String key) {
56          return getter.get().get(key);
57      }
58  
59      @Override
60      public String getProperty(String key, String defaultValue) {
61          return getter.get().getOrDefault(key, defaultValue);
62      }
63  
64      @Override
65      public Enumeration<?> propertyNames() {
66          return Collections.enumeration(getter.get().keySet());
67      }
68  
69      @Override
70      public Set<String> stringPropertyNames() {
71          return getter.get().keySet();
72      }
73  
74      @Override
75      public void list(PrintStream out) {
76          throw new UnsupportedOperationException();
77      }
78  
79      @Override
80      public void list(PrintWriter out) {
81          throw new UnsupportedOperationException();
82      }
83  
84      @Override
85      public int size() {
86          return getter.get().size();
87      }
88  
89      @Override
90      public boolean isEmpty() {
91          return getter.get().isEmpty();
92      }
93  
94      @Override
95      public Enumeration<Object> keys() {
96          return Collections.enumeration((Set) getter.get().keySet());
97      }
98  
99      @Override
100     public Enumeration<Object> elements() {
101         return Collections.enumeration((Collection) getter.get().values());
102     }
103 
104     @Override
105     public boolean contains(Object value) {
106         return getter.get().containsKey(value != null ? value.toString() : null);
107     }
108 
109     @Override
110     public boolean containsValue(Object value) {
111         return getter.get().containsValue(value);
112     }
113 
114     @Override
115     public boolean containsKey(Object key) {
116         return getter.get().containsKey(key);
117     }
118 
119     @Override
120     public Object get(Object key) {
121         return getter.get().get(key);
122     }
123 
124     @Override
125     public synchronized String toString() {
126         return getter.get().toString();
127     }
128 
129     @Override
130     public Set<Object> keySet() {
131         return (Set) getter.get().keySet();
132     }
133 
134     @Override
135     public Collection<Object> values() {
136         return (Collection) getter.get().values();
137     }
138 
139     @Override
140     public Set<Map.Entry<Object, Object>> entrySet() {
141         Set<Map.Entry<String, String>> set = getter.get().entrySet();
142         return new AbstractSet<Map.Entry<Object, Object>>() {
143             @Override
144             public Iterator<Map.Entry<Object, Object>> iterator() {
145                 Iterator<Map.Entry<String, String>> it = set.iterator();
146                 return new Iterator<Map.Entry<Object, Object>>() {
147                     @Override
148                     public boolean hasNext() {
149                         return it.hasNext();
150                     }
151 
152                     @Override
153                     public Map.Entry<Object, Object> next() {
154                         Map.Entry<String, String> entry = it.next();
155                         return new Map.Entry<Object, Object>() {
156                             @Override
157                             public Object getKey() {
158                                 return entry.getKey();
159                             }
160 
161                             @Override
162                             public Object getValue() {
163                                 return entry.getValue();
164                             }
165 
166                             @Override
167                             public Object setValue(Object value) {
168                                 return writeOperation(p -> p.put(entry.getKey(), value));
169                             }
170                         };
171                     }
172                 };
173             }
174 
175             @Override
176             public int size() {
177                 return set.size();
178             }
179         };
180     }
181 
182     @Override
183     public synchronized boolean equals(Object o) {
184         if (o instanceof WrapperProperties wrapperProperties) {
185             o = wrapperProperties.getter.get();
186         }
187         return getter.get().equals(o);
188     }
189 
190     @Override
191     public synchronized int hashCode() {
192         return getter.get().hashCode();
193     }
194 
195     @Override
196     public Object getOrDefault(Object key, Object defaultValue) {
197         return getter.get().getOrDefault(key, defaultValue != null ? defaultValue.toString() : null);
198     }
199 
200     @Override
201     public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) {
202         getter.get().forEach(action);
203     }
204 
205     interface WriteOp<T> {
206         T perform(Properties props);
207     }
208 
209     interface WriteOpVoid {
210         void perform(Properties props);
211     }
212 
213     private <T> T writeOperation(WriteOp<T> runner) {
214         Properties props = new Properties();
215         props.putAll(getter.get());
216         T ret = runner.perform(props);
217         if (!props.equals(getter.get())) {
218             setter.accept(props);
219         }
220         return ret;
221     }
222 
223     private void writeOperationVoid(WriteOpVoid runner) {
224         Properties props = new Properties();
225         props.putAll(getter.get());
226         runner.perform(props);
227         if (!props.equals(getter.get())) {
228             setter.accept(props);
229         }
230     }
231 
232     @Override
233     public synchronized Object setProperty(String key, String value) {
234         return writeOperation(p -> p.setProperty(key, value));
235     }
236 
237     @Override
238     public synchronized Object put(Object key, Object value) {
239         return writeOperation(p -> p.put(key, value));
240     }
241 
242     @Override
243     public synchronized Object remove(Object key) {
244         return writeOperation(p -> p.remove(key));
245     }
246 
247     @Override
248     public synchronized void putAll(Map<?, ?> t) {
249         writeOperationVoid(p -> p.putAll(t));
250     }
251 
252     @Override
253     public synchronized void clear() {
254         writeOperationVoid(Properties::clear);
255     }
256 
257     @Override
258     public synchronized void replaceAll(BiFunction<? super Object, ? super Object, ?> function) {
259         writeOperationVoid(p -> p.replaceAll(function));
260     }
261 
262     @Override
263     public synchronized Object putIfAbsent(Object key, Object value) {
264         return writeOperation(p -> p.putIfAbsent(key, value));
265     }
266 
267     @Override
268     public synchronized boolean remove(Object key, Object value) {
269         return writeOperation(p -> p.remove(key, value));
270     }
271 
272     @Override
273     public synchronized boolean replace(Object key, Object oldValue, Object newValue) {
274         return writeOperation(p -> p.replace(key, oldValue, newValue));
275     }
276 
277     @Override
278     public synchronized Object replace(Object key, Object value) {
279         return writeOperation(p -> p.replace(key, value));
280     }
281 
282     @Override
283     public synchronized Object computeIfAbsent(Object key, Function<? super Object, ?> mappingFunction) {
284         return writeOperation(p -> p.computeIfAbsent(key, mappingFunction));
285     }
286 
287     @Override
288     public synchronized Object computeIfPresent(
289             Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
290         return writeOperation(p -> p.computeIfPresent(key, remappingFunction));
291     }
292 
293     @Override
294     public synchronized Object compute(Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
295         return writeOperation(p -> p.compute(key, remappingFunction));
296     }
297 
298     @Override
299     public synchronized Object merge(
300             Object key, Object value, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
301         return writeOperation(p -> p.merge(key, value, remappingFunction));
302     }
303 
304     @Override
305     public synchronized void load(Reader reader) throws IOException {
306         try {
307             writeOperationVoid(p -> {
308                 try {
309                     p.load(reader);
310                 } catch (IOException e) {
311                     throw new IOError(e);
312                 }
313             });
314         } catch (IOError e) {
315             throw (IOException) e.getCause();
316         }
317     }
318 
319     @Override
320     public synchronized void load(InputStream inStream) throws IOException {
321         try {
322             writeOperationVoid(p -> {
323                 try {
324                     p.load(inStream);
325                 } catch (IOException e) {
326                     throw new IOError(e);
327                 }
328             });
329         } catch (IOError e) {
330             throw (IOException) e.getCause();
331         }
332     }
333 
334     @Override
335     public void save(OutputStream out, String comments) {
336         Properties props = new Properties();
337         props.putAll(getter.get());
338         props.save(out, comments);
339     }
340 
341     @Override
342     public void store(Writer writer, String comments) throws IOException {
343         Properties props = new Properties();
344         props.putAll(getter.get());
345         props.store(writer, comments);
346     }
347 
348     @Override
349     public void store(OutputStream out, String comments) throws IOException {
350         Properties props = new Properties();
351         props.putAll(getter.get());
352         props.store(out, comments);
353     }
354 
355     @Override
356     public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException {
357         throw new UnsupportedOperationException();
358     }
359 
360     @Override
361     public void storeToXML(OutputStream os, String comment) throws IOException {
362         Properties props = new Properties();
363         props.putAll(getter.get());
364         props.storeToXML(os, comment);
365     }
366 
367     @Override
368     public void storeToXML(OutputStream os, String comment, String encoding) throws IOException {
369         Properties props = new Properties();
370         props.putAll(getter.get());
371         props.storeToXML(os, comment, encoding);
372     }
373 
374 
375     private Object writeReplace() throws java.io.ObjectStreamException {
376         Properties props = new Properties();
377         props.putAll(getter.get());
378         return props;
379     }
380 }