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.Collection;
30  import java.util.Collections;
31  import java.util.Enumeration;
32  import java.util.InvalidPropertiesFormatException;
33  import java.util.Map;
34  import java.util.Properties;
35  import java.util.Set;
36  import java.util.function.BiConsumer;
37  import java.util.function.BiFunction;
38  import java.util.function.Consumer;
39  import java.util.function.Function;
40  import java.util.function.Supplier;
41  
42  class WrapperProperties extends Properties {
43  
44      final Supplier<Map<String, String>> getter;
45      final Consumer<Properties> setter;
46  
47      WrapperProperties(Supplier<Map<String, String>> getter, Consumer<Properties> setter) {
48          this.getter = getter;
49          this.setter = setter;
50      }
51  
52      @Override
53      public String getProperty(String key) {
54          return getter.get().get(key);
55      }
56  
57      @Override
58      public String getProperty(String key, String defaultValue) {
59          return getter.get().getOrDefault(key, defaultValue);
60      }
61  
62      @Override
63      public Enumeration<?> propertyNames() {
64          return Collections.enumeration(getter.get().keySet());
65      }
66  
67      @Override
68      public Set<String> stringPropertyNames() {
69          return getter.get().keySet();
70      }
71  
72      @Override
73      public void list(PrintStream out) {
74          throw new UnsupportedOperationException();
75      }
76  
77      @Override
78      public void list(PrintWriter out) {
79          throw new UnsupportedOperationException();
80      }
81  
82      @Override
83      public int size() {
84          return getter.get().size();
85      }
86  
87      @Override
88      public boolean isEmpty() {
89          return getter.get().isEmpty();
90      }
91  
92      @Override
93      public Enumeration<Object> keys() {
94          return Collections.enumeration((Set) getter.get().keySet());
95      }
96  
97      @Override
98      public Enumeration<Object> elements() {
99          return Collections.enumeration((Collection) getter.get().values());
100     }
101 
102     @Override
103     public boolean contains(Object value) {
104         return getter.get().containsKey(value != null ? value.toString() : null);
105     }
106 
107     @Override
108     public boolean containsValue(Object value) {
109         return getter.get().containsValue(value);
110     }
111 
112     @Override
113     public boolean containsKey(Object key) {
114         return getter.get().containsKey(key);
115     }
116 
117     @Override
118     public Object get(Object key) {
119         return getter.get().get(key);
120     }
121 
122     @Override
123     public synchronized String toString() {
124         return getter.get().toString();
125     }
126 
127     @Override
128     public Set<Object> keySet() {
129         return (Set) getter.get().keySet();
130     }
131 
132     @Override
133     public Collection<Object> values() {
134         return (Collection) getter.get().values();
135     }
136 
137     @Override
138     public Set<Map.Entry<Object, Object>> entrySet() {
139         return (Set) getter.get().entrySet();
140     }
141 
142     @Override
143     public synchronized boolean equals(Object o) {
144         if (o instanceof WrapperProperties) {
145             o = ((WrapperProperties) o).getter.get();
146         }
147         return getter.get().equals(o);
148     }
149 
150     @Override
151     public synchronized int hashCode() {
152         return getter.get().hashCode();
153     }
154 
155     @Override
156     public Object getOrDefault(Object key, Object defaultValue) {
157         return getter.get().getOrDefault(key, defaultValue != null ? defaultValue.toString() : null);
158     }
159 
160     @Override
161     public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) {
162         getter.get().forEach(action);
163     }
164 
165     interface WriteOp<T> {
166         T perform(Properties props);
167     }
168 
169     interface WriteOpVoid {
170         void perform(Properties props);
171     }
172 
173     private <T> T writeOperation(WriteOp<T> runner) {
174         Properties props = new Properties();
175         props.putAll(getter.get());
176         T ret = runner.perform(props);
177         if (!props.equals(getter.get())) {
178             setter.accept(props);
179         }
180         return ret;
181     }
182 
183     private void writeOperationVoid(WriteOpVoid runner) {
184         Properties props = new Properties();
185         props.putAll(getter.get());
186         runner.perform(props);
187         if (!props.equals(getter.get())) {
188             setter.accept(props);
189         }
190     }
191 
192     @Override
193     public synchronized Object setProperty(String key, String value) {
194         return writeOperation(p -> p.setProperty(key, value));
195     }
196 
197     @Override
198     public synchronized Object put(Object key, Object value) {
199         return writeOperation(p -> p.put(key, value));
200     }
201 
202     @Override
203     public synchronized Object remove(Object key) {
204         return writeOperation(p -> p.remove(key));
205     }
206 
207     @Override
208     public synchronized void putAll(Map<?, ?> t) {
209         writeOperationVoid(p -> p.putAll(t));
210     }
211 
212     @Override
213     public synchronized void clear() {
214         writeOperationVoid(Properties::clear);
215     }
216 
217     @Override
218     public synchronized void replaceAll(BiFunction<? super Object, ? super Object, ?> function) {
219         writeOperationVoid(p -> p.replaceAll(function));
220     }
221 
222     @Override
223     public synchronized Object putIfAbsent(Object key, Object value) {
224         return writeOperation(p -> p.putIfAbsent(key, value));
225     }
226 
227     @Override
228     public synchronized boolean remove(Object key, Object value) {
229         return writeOperation(p -> p.remove(key, value));
230     }
231 
232     @Override
233     public synchronized boolean replace(Object key, Object oldValue, Object newValue) {
234         return writeOperation(p -> p.replace(key, oldValue, newValue));
235     }
236 
237     @Override
238     public synchronized Object replace(Object key, Object value) {
239         return writeOperation(p -> p.replace(key, value));
240     }
241 
242     @Override
243     public synchronized Object computeIfAbsent(Object key, Function<? super Object, ?> mappingFunction) {
244         return writeOperation(p -> p.computeIfAbsent(key, mappingFunction));
245     }
246 
247     @Override
248     public synchronized Object computeIfPresent(
249             Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
250         return writeOperation(p -> p.computeIfPresent(key, remappingFunction));
251     }
252 
253     @Override
254     public synchronized Object compute(Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
255         return writeOperation(p -> p.compute(key, remappingFunction));
256     }
257 
258     @Override
259     public synchronized Object merge(
260             Object key, Object value, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
261         return writeOperation(p -> p.merge(key, value, remappingFunction));
262     }
263 
264     @Override
265     public synchronized void load(Reader reader) throws IOException {
266         try {
267             writeOperationVoid(p -> {
268                 try {
269                     p.load(reader);
270                 } catch (IOException e) {
271                     throw new IOError(e);
272                 }
273             });
274         } catch (IOError e) {
275             throw (IOException) e.getCause();
276         }
277     }
278 
279     @Override
280     public synchronized void load(InputStream inStream) throws IOException {
281         try {
282             writeOperationVoid(p -> {
283                 try {
284                     p.load(inStream);
285                 } catch (IOException e) {
286                     throw new IOError(e);
287                 }
288             });
289         } catch (IOError e) {
290             throw (IOException) e.getCause();
291         }
292     }
293 
294     @Override
295     public void save(OutputStream out, String comments) {
296         Properties props = new Properties();
297         props.putAll(getter.get());
298         props.save(out, comments);
299     }
300 
301     @Override
302     public void store(Writer writer, String comments) throws IOException {
303         Properties props = new Properties();
304         props.putAll(getter.get());
305         props.store(writer, comments);
306     }
307 
308     @Override
309     public void store(OutputStream out, String comments) throws IOException {
310         Properties props = new Properties();
311         props.putAll(getter.get());
312         props.store(out, comments);
313     }
314 
315     @Override
316     public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException {
317         throw new UnsupportedOperationException();
318     }
319 
320     @Override
321     public void storeToXML(OutputStream os, String comment) throws IOException {
322         Properties props = new Properties();
323         props.putAll(getter.get());
324         props.storeToXML(os, comment);
325     }
326 
327     @Override
328     public void storeToXML(OutputStream os, String comment, String encoding) throws IOException {
329         Properties props = new Properties();
330         props.putAll(getter.get());
331         props.storeToXML(os, comment, encoding);
332     }
333 }