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