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      * @param source
107      * @return all overwritten property names (may be empty if there was no property name clash)
108      */
109     public Collection<String> copyPropertiesFrom(Properties source) {
110         if (source != null) {
111             return putAllInternal(source);
112         } else {
113             return Collections.emptyList();
114         }
115     }
116 
117     /**
118      * Copies all keys and values from source to these properties, overwriting existing properties with same name
119      * @param source
120      * @return all overwritten property names (may be empty if there was no property name clash)
121      */
122     public Collection<String> copyPropertiesFrom(Map<String, String> source) {
123         return copyProperties(this, source);
124     }
125 
126     public Iterable<Object> getStringKeySet() {
127         return keySet();
128     }
129 
130     public Set<Object> propertiesThatCannotBeSetASystemProperties() {
131         Set<Object> result = new HashSet<>();
132         for (Object key : getStringKeySet()) {
133             //noinspection SuspiciousMethodCalls
134             if (KEYS_THAT_CANNOT_BE_USED_AS_SYSTEM_PROPERTIES.contains(key)) {
135                 result.add(key);
136             }
137         }
138         return result;
139     }
140 
141     public void copyToSystemProperties() {
142         for (Object o : items) {
143             String key = (String) o;
144             String value = getProperty(key);
145             System.setProperty(key, value);
146         }
147     }
148 
149     private static Collection<String> copyProperties(Properties target, Map<String, String> source) {
150         Collection<String> overwrittenProperties = new LinkedList<>();
151         if (source != null) {
152             for (String key : source.keySet()) {
153                 String value = source.get(key);
154                 if (target.setProperty(key, value == null ? "" : value) != null) {
155                     overwrittenProperties.add(key);
156                 }
157             }
158         }
159         return overwrittenProperties;
160     }
161 
162     @Override
163     public void copyTo(Map<Object, Object> target) {
164         target.putAll(this);
165     }
166 
167     public void setProperty(String key, File file) {
168         if (file != null) {
169             setProperty(key, file.toString());
170         }
171     }
172 
173     public void setProperty(String key, Boolean aBoolean) {
174         if (aBoolean != null) {
175             setProperty(key, aBoolean.toString());
176         }
177     }
178 
179     public void setProperty(String key, int value) {
180         setProperty(key, String.valueOf(value));
181     }
182 
183     public void setProperty(String key, Long value) {
184         if (value != null) {
185             setProperty(key, value.toString());
186         }
187     }
188 
189     public void addList(List<?> items, String propertyPrefix) {
190         if (items != null && !items.isEmpty()) {
191             int i = 0;
192             for (Object item : items) {
193                 if (item == null) {
194                     throw new NullPointerException(propertyPrefix + i + " has null value");
195                 }
196 
197                 String[] stringArray = StringUtils.split(item.toString(), ",");
198 
199                 for (String aStringArray : stringArray) {
200                     setProperty(propertyPrefix + i, aStringArray);
201                     i++;
202                 }
203             }
204         }
205     }
206 
207     public void setClasspath(String prefix, Classpath classpath) {
208         List<String> classpathElements = classpath.getClassPath();
209         for (int i = 0; i < classpathElements.size(); ++i) {
210             String element = classpathElements.get(i);
211             setProperty(prefix + i, element);
212         }
213     }
214 
215     private static SurefireProperties loadProperties(InputStream inStream) throws IOException {
216         try (InputStream surefirePropertiesStream = inStream) {
217             Properties p = new Properties();
218             p.load(surefirePropertiesStream);
219             return new SurefireProperties(p);
220         }
221     }
222 
223     public static SurefireProperties loadProperties(File file) throws IOException {
224         return file == null ? new SurefireProperties() : loadProperties(new FileInputStream(file));
225     }
226 
227     public void setNullableProperty(String key, String value) {
228         if (value != null) {
229             super.setProperty(key, value);
230         }
231     }
232 }