PropertiesReader.java
001 /*
002  * Copyright 2008-2017 the original author or authors.
003  *
004  * Licensed under the Apache License, Version 2.0 (the "License");
005  * you may not use this file except in compliance with the License.
006  * You may obtain a copy of the License at
007  *
008  *     http://www.apache.org/licenses/LICENSE-2.0
009  *
010  * Unless required by applicable law or agreed to in writing, software
011  * distributed under the License is distributed on an "AS IS" BASIS,
012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  * See the License for the specific language governing permissions and
014  * limitations under the License.
015  */
016 package griffon.util;
017 
018 import griffon.core.env.Environment;
019 import griffon.core.env.Metadata;
020 
021 import javax.annotation.Nonnull;
022 import javax.annotation.Nullable;
023 import javax.inject.Inject;
024 import java.io.IOException;
025 import java.io.InputStream;
026 import java.io.Reader;
027 import java.net.URL;
028 import java.util.Collections;
029 import java.util.LinkedHashMap;
030 import java.util.Map;
031 import java.util.Properties;
032 
033 import static griffon.util.GriffonNameUtils.isBlank;
034 import static java.util.Objects.requireNonNull;
035 
036 /**
037  @author Andres Almiray
038  @since 2.10.0
039  */
040 public class PropertiesReader {
041     private static final String ENVIRONMENTS_METHOD = "environments";
042 
043     private final Map<String, String> conditionValues = new LinkedHashMap<>();
044 
045     public static class Provider implements javax.inject.Provider<PropertiesReader> {
046         @Inject private Metadata metadata;
047         @Inject private Environment environment;
048 
049         @Override
050         public PropertiesReader get() {
051             PropertiesReader propertiesReader = new PropertiesReader();
052             propertiesReader.registerConditionalBlock("environments", environment.getName());
053             propertiesReader.registerConditionalBlock("projects", metadata.getApplicationName());
054             propertiesReader.registerConditionalBlock("platforms", GriffonApplicationUtils.getPlatform());
055             return propertiesReader;
056         }
057     }
058 
059     public void registerConditionalBlock(@Nullable String blockName, @Nullable String blockValue) {
060         if (!isBlank(blockName)) {
061             if (isBlank(blockValue)) {
062                 conditionValues.remove(blockName);
063             else {
064                 conditionValues.put(blockName, blockValue);
065             }
066         }
067     }
068 
069     @Nonnull
070     public Map<String, String> getConditionalBlockValues() {
071         return Collections.unmodifiableMap(conditionValues);
072     }
073 
074     @Nonnull
075     public String getEnvironment() {
076         return conditionValues.get(ENVIRONMENTS_METHOD);
077     }
078 
079     public void setEnvironment(String environment) {
080         conditionValues.put(ENVIRONMENTS_METHOD, environment);
081     }
082 
083     @Nonnull
084     public Properties load(@Nonnull URL locationthrows IOException {
085         return load(requireNonNull(location, "Argument 'location' must not be null").openStream());
086     }
087 
088     @Nonnull
089     public Properties load(@Nonnull InputStream streamthrows IOException {
090         Properties p = new Properties();
091         p.load(stream);
092         return processProperties(p);
093     }
094 
095     @Nonnull
096     public Properties load(@Nonnull Reader readerthrows IOException {
097         Properties p = new Properties();
098         p.load(reader);
099         return processProperties(p);
100     }
101 
102     @Nonnull
103     protected Properties processProperties(@Nonnull Properties input) {
104         Properties output = new Properties();
105 
106         for (String key : input.stringPropertyNames()) {
107             ConditionalBlockMatch match = resolveConditionalBlockMatch(key);
108             if (match != null) {
109                 if (match.key != null) {
110                     output.put(match.key, input.getProperty(key));
111                 }
112             else {
113                 output.put(key, input.getProperty(key));
114             }
115         }
116 
117         return output;
118     }
119 
120     @Nullable
121     private ConditionalBlockMatch resolveConditionalBlockMatch(@Nonnull String key) {
122         for (Map.Entry<String, String> e : conditionValues.entrySet()) {
123             String blockName = e.getKey();
124             if (!key.startsWith(blockName + ".")) {
125                 continue;
126             }
127 
128             String prefix = blockName + "." + e.getValue() ".";
129             if (key.startsWith(prefix)) {
130                 String subkey = key.substring(prefix.length());
131                 ConditionalBlockMatch match = resolveConditionalBlockMatch(subkey);
132                 if (match == null) {
133                     match = new ConditionalBlockMatch(subkey);
134                 }
135                 return match;
136             else {
137                 return new ConditionalBlockMatch(null);
138             }
139         }
140 
141         return null;
142     }
143 
144     private static class ConditionalBlockMatch {
145         public final String key;
146 
147         private ConditionalBlockMatch(String key) {
148             this.key = key;
149         }
150     }
151 }