DelegatingMutableConfiguration.java
001 /*
002  * Copyright 2008-2016 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 org.codehaus.griffon.runtime.core;
017 
018 import griffon.core.Configuration;
019 import griffon.core.MutableConfiguration;
020 import griffon.util.AbstractMapResourceBundle;
021 import griffon.util.CompositeResourceBundle;
022 import griffon.util.ConfigUtils;
023 
024 import javax.annotation.Nonnull;
025 import javax.annotation.Nullable;
026 import java.util.LinkedHashMap;
027 import java.util.LinkedHashSet;
028 import java.util.Map;
029 import java.util.MissingResourceException;
030 import java.util.ResourceBundle;
031 import java.util.Set;
032 
033 import static griffon.util.ConfigUtils.getConfigValue;
034 import static griffon.util.GriffonNameUtils.requireNonBlank;
035 import static java.util.Arrays.asList;
036 import static java.util.Collections.unmodifiableMap;
037 import static java.util.Objects.requireNonNull;
038 
039 /**
040  @author Andres Almiray
041  @since 2.2.0
042  */
043 public class DelegatingMutableConfiguration extends ConfigurationDecorator implements MutableConfiguration {
044     private static final String ERROR_KEY_BLANK = "Argument 'key' must not be blank";
045     private static final String ERROR_VALUE_NULL = "Argument 'value' must not be null";
046 
047     private final Map<String, Object> mutableKeyValues = new LinkedHashMap<>();
048     private final Set<String> removedKeys = new LinkedHashSet<>();
049 
050     public DelegatingMutableConfiguration(@Nonnull Configuration delegate) {
051         super(delegate);
052     }
053 
054     @Override
055     public void set(@Nonnull String key, @Nonnull Object value) {
056         requireNonBlank(key, ERROR_KEY_BLANK);
057         requireNonNull(value, ERROR_VALUE_NULL);
058         mutableKeyValues.put(key, value);
059     }
060 
061     @Nullable
062     @Override
063     public Object remove(@Nonnull String key) {
064         requireNonBlank(key, ERROR_KEY_BLANK);
065         if (mutableKeyValues.containsKey(key)) {
066             removedKeys.add(key);
067             return mutableKeyValues.remove(key);
068         else if (!removedKeys.contains(key&& delegate.containsKey(key)) {
069             removedKeys.add(key);
070             return delegate.get(key);
071         }
072         return null;
073     }
074 
075     @Nullable
076     @Override
077     @SuppressWarnings("unchecked")
078     public <T> T removeAs(@Nonnull String key) {
079         return (Tremove(key);
080     }
081 
082     @Nullable
083     @Override
084     @SuppressWarnings("unchecked")
085     public <T> T removeConverted(@Nonnull String key, @Nonnull Class<T> type) {
086         return convertValue(remove(key), type);
087     }
088 
089     @Nonnull
090     @Override
091     public Map<String, Object> asFlatMap() {
092         Map<String, Object> flatMap = new LinkedHashMap<>(delegate.asFlatMap());
093         flatMap.putAll(mutableKeyValues);
094         for (String removedKey : removedKeys) {
095             flatMap.remove(removedKey);
096         }
097         return unmodifiableMap(flatMap);
098     }
099 
100     @Nonnull
101     @Override
102     public ResourceBundle asResourceBundle() {
103         return new CompositeResourceBundle(asList(new PrivateMapResourceBundle(asFlatMap()), delegate.asResourceBundle()));
104     }
105 
106     @Nullable
107     @Override
108     public Object get(@Nonnull String key) {
109         requireNonBlank(key, ERROR_KEY_BLANK);
110         try {
111             return getConfigValue(mutableKeyValues, key);
112         catch (MissingResourceException mre) {
113             if (removedKeys.contains(key)) {
114                 return null;
115             }
116             return super.get(key);
117         }
118     }
119 
120     @Nullable
121     @Override
122     public <T> T get(@Nonnull String key, @Nullable T defaultValue) {
123         T value = (Tget(key);
124         return value != null ? value : defaultValue;
125     }
126 
127     @Nullable
128     @Override
129     public String getAsString(@Nonnull String key, @Nullable String defaultValue) {
130         Object value = get(key);
131         return value != null ? String.valueOf(value: defaultValue;
132     }
133 
134     @Override
135     public boolean containsKey(@Nonnull String key) {
136         requireNonBlank(key, ERROR_KEY_BLANK);
137         return ConfigUtils.containsKey(mutableKeyValues, key|| (!removedKeys.contains(key&& delegate.containsKey(key));
138     }
139 
140     private static class PrivateMapResourceBundle extends AbstractMapResourceBundle {
141         private final Map<String, Object> map = new LinkedHashMap<>();
142 
143         private PrivateMapResourceBundle(Map<String, Object> map) {
144             this.map.putAll(map);
145             initialize(entries);
146             initializeKeys();
147         }
148 
149         @Override
150         protected void initialize(@Nonnull Map<String, Object> entries) {
151             if (map != null && entries != null) {
152                 entries.putAll(map);
153             }
154         }
155     }
156 }