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.plugin.surefire;
20  
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.Enumeration;
28  import java.util.HashSet;
29  import java.util.LinkedHashSet;
30  import java.util.LinkedList;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.Properties;
34  import java.util.Set;
35  
36  import org.apache.maven.surefire.booter.Classpath;
37  import org.apache.maven.surefire.booter.KeyValueSource;
38  import org.apache.maven.surefire.shared.utils.StringUtils;
39  
40  import static java.util.Arrays.asList;
41  import static java.util.Map.Entry;
42  
43  /**
44   * A {@link Properties} implementation that preserves insertion order.
45   */
46  public class SurefireProperties extends Properties implements KeyValueSource {
47      private static final Collection<String> KEYS_THAT_CANNOT_BE_USED_AS_SYSTEM_PROPERTIES =
48              asList("java.library.path", "file.encoding", "jdk.map.althashing.threshold", "line.separator");
49  
50      private final LinkedHashSet<Object> items = new LinkedHashSet<>();
51  
52      public SurefireProperties() {}
53  
54      public SurefireProperties(Properties source) {
55          if (source != null) {
56              putAll(source);
57          }
58      }
59  
60      public SurefireProperties(KeyValueSource source) {
61          if (source != null) {
62              source.copyTo(this);
63          }
64      }
65  
66      @Override
67      public synchronized void putAll(Map<?, ?> t) {
68          putAllInternal(t);
69      }
70  
71      private Collection<String> putAllInternal(Map<?, ?> source) {
72          Collection<String> overwrittenProperties = new LinkedList<>();
73          for (Entry<?, ?> entry : source.entrySet()) {
74              if (put(entry.getKey(), entry.getValue()) != null) {
75                  overwrittenProperties.add(entry.getKey().toString());
76              }
77          }
78          return overwrittenProperties;
79      }
80  
81      @Override
82      public synchronized Object put(Object key, Object value) {
83          items.add(key);
84          return super.put(key, value);
85      }
86  
87      @Override
88      public synchronized Object remove(Object key) {
89          items.remove(key);
90          return super.remove(key);
91      }
92  
93      @Override
94      public synchronized void clear() {
95          items.clear();
96          super.clear();
97      }
98  
99      @Override
100     public synchronized Enumeration<Object> keys() {
101         return Collections.enumeration(items);
102     }
103 
104     /**
105      * Copies all keys and values from source to these properties, overwriting existing properties with same name.
106      *
107      * @param source
108      * @return all overwritten property names (may be empty if there was no property name clash)
109      */
110     public Collection<String> copyPropertiesFrom(Properties source) {
111         if (source != null) {
112             return putAllInternal(source);
113         } else {
114             return Collections.emptyList();
115         }
116     }
117 
118     /**
119      * Copies all keys and values from source to these properties, overwriting existing properties with same name.
120      *
121      * @param source
122      * @return all overwritten property names (may be empty if there was no property name clash)
123      */
124     public Collection<String> copyPropertiesFrom(Map<String, String> source) {
125         return copyProperties(this, source);
126     }
127 
128     public Iterable<Object> getStringKeySet() {
129         return keySet();
130     }
131 
132     public Set<Object> propertiesThatCannotBeSetASystemProperties() {
133         Set<Object> result = new HashSet<>();
134         for (Object key : getStringKeySet()) {
135             //noinspection SuspiciousMethodCalls
136             if (KEYS_THAT_CANNOT_BE_USED_AS_SYSTEM_PROPERTIES.contains(key)) {
137                 result.add(key);
138             }
139         }
140         return result;
141     }
142 
143     public void copyToSystemProperties() {
144         for (Object o : items) {
145             String key = (String) o;
146             String value = getProperty(key);
147             System.setProperty(key, value);
148         }
149     }
150 
151     private static Collection<String> copyProperties(Properties target, Map<String, String> source) {
152         Collection<String> overwrittenProperties = new LinkedList<>();
153         if (source != null) {
154             for (String key : source.keySet()) {
155                 String value = source.get(key);
156                 if (target.setProperty(key, value == null ? "" : value) != null) {
157                     overwrittenProperties.add(key);
158                 }
159             }
160         }
161         return overwrittenProperties;
162     }
163 
164     @Override
165     public void copyTo(Map<Object, Object> target) {
166         target.putAll(this);
167     }
168 
169     public void setProperty(String key, File file) {
170         if (file != null) {
171             setProperty(key, file.toString());
172         }
173     }
174 
175     public void setProperty(String key, Boolean aBoolean) {
176         if (aBoolean != null) {
177             setProperty(key, aBoolean.toString());
178         }
179     }
180 
181     public void setProperty(String key, int value) {
182         setProperty(key, String.valueOf(value));
183     }
184 
185     public void setProperty(String key, Long value) {
186         if (value != null) {
187             setProperty(key, value.toString());
188         }
189     }
190 
191     public void addList(List<?> items, String propertyPrefix) {
192         if (items != null && !items.isEmpty()) {
193             int i = 0;
194             for (Object item : items) {
195                 if (item == null) {
196                     throw new NullPointerException(propertyPrefix + i + " has null value");
197                 }
198 
199                 String[] stringArray = StringUtils.split(item.toString(), ",");
200 
201                 for (String aStringArray : stringArray) {
202                     setProperty(propertyPrefix + i, aStringArray);
203                     i++;
204                 }
205             }
206         }
207     }
208 
209     public void setClasspath(String prefix, Classpath classpath) {
210         List<String> classpathElements = classpath.getClassPath();
211         for (int i = 0; i < classpathElements.size(); ++i) {
212             String element = classpathElements.get(i);
213             setProperty(prefix + i, element);
214         }
215     }
216 
217     private static SurefireProperties loadProperties(InputStream inStream) throws IOException {
218         try (InputStream surefirePropertiesStream = inStream) {
219             Properties p = new Properties();
220             p.load(surefirePropertiesStream);
221             return new SurefireProperties(p);
222         }
223     }
224 
225     public static SurefireProperties loadProperties(File file) throws IOException {
226         return file == null ? new SurefireProperties() : loadProperties(new FileInputStream(file));
227     }
228 
229     public void setNullableProperty(String key, String value) {
230         if (value != null) {
231             super.setProperty(key, value);
232         }
233     }
234 }