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