1 package org.robolectric.plugins;
2 
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.util.LinkedHashMap;
6 import java.util.Map;
7 import java.util.Properties;
8 import javax.annotation.Nonnull;
9 import org.robolectric.pluginapi.config.Configurer;
10 
11 /**
12  * Provides cached access to {@code robolectric-properties} files, for all your configuration needs!
13  *
14  * <p>Used by {@link ConfigConfigurer} to support package configuration (see [Configuring
15  * Robolectric](http://robolectric.org/configuring/) but it may be useful for other {@link
16  * Configurer}s as well.
17  */
18 @SuppressWarnings({"AndroidJdkLibsChecker", "NewApi"})
19 public class PackagePropertiesLoader {
20 
21   /**
22    * We should get very high cache hit rates even with a tiny cache if we're called sequentially by
23    * multiple {@link Configurer}s for the same package.
24    */
25   private final Map<String, Properties> cache =
26       new LinkedHashMap<String, Properties>() {
27         @Override
28         protected boolean removeEldestEntry(Map.Entry<String, Properties> eldest) {
29           return size() > 3;
30         }
31       };
32 
getConfig(@onnull String packageName, String propFileName)33   private Properties getConfig(@Nonnull String packageName, String propFileName) {
34     StringBuilder buf = new StringBuilder();
35     if (!packageName.isEmpty()) {
36       buf.append(packageName.replace('.', '/'));
37       buf.append('/');
38     }
39     String propsFile = buf.toString() + propFileName + ".properties";
40     return cache.computeIfAbsent(
41         propsFile,
42         s -> {
43           final String resourceName = propsFile;
44           try (InputStream resourceAsStream = getResourceAsStream(resourceName)) {
45             if (resourceAsStream == null) {
46               return null;
47             }
48             Properties properties = new Properties();
49             properties.load(resourceAsStream);
50             return properties;
51           } catch (IOException e) {
52             throw new RuntimeException(e);
53           }
54         });
55   }
56 
57   /**
58    * Return a {@link Properties} file for the given package name, or {@code null} if none is
59    * available.
60    *
61    * @since 3.2
62    */
getConfigProperties(@onnull String packageName)63   public Properties getConfigProperties(@Nonnull String packageName) {
64     return getConfig(packageName, "robolectric");
65   }
66 
67   // visible for testing
getResourceAsStream(String resourceName)68   InputStream getResourceAsStream(String resourceName) {
69     return getClass().getClassLoader().getResourceAsStream(resourceName);
70   }
71 }
72