DelegatingMutableConfiguration.java
001 /*
002  * Copyright 2008-2015 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     @Nonnull
076     @Override
077     public Map<String, Object> asFlatMap() {
078         Map<String, Object> flatMap = new LinkedHashMap<>(delegate.asFlatMap());
079         flatMap.putAll(mutableKeyValues);
080         for (String removedKey : removedKeys) {
081             flatMap.remove(removedKey);
082         }
083         return unmodifiableMap(flatMap);
084     }
085 
086     @Nonnull
087     @Override
088     public ResourceBundle asResourceBundle() {
089         return new CompositeResourceBundle(asList(new PrivateMapResourceBundle(asFlatMap()), delegate.asResourceBundle()));
090     }
091 
092     @Nullable
093     @Override
094     public Object get(@Nonnull String key) {
095         requireNonBlank(key, ERROR_KEY_BLANK);
096         try {
097             return getConfigValue(mutableKeyValues, key);
098         catch (MissingResourceException mre) {
099             if (removedKeys.contains(key)) {
100                 return null;
101             }
102             return super.get(key);
103         }
104     }
105 
106     @Nullable
107     @Override
108     public <T> T get(@Nonnull String key, @Nullable T defaultValue) {
109         T value = (Tget(key);
110         return value != null ? value : defaultValue;
111     }
112 
113     @Nullable
114     @Override
115     public String getAsString(@Nonnull String key, @Nullable String defaultValue) {
116         Object value = get(key);
117         return value != null ? String.valueOf(value: defaultValue;
118     }
119 
120     @Override
121     public boolean containsKey(@Nonnull String key) {
122         requireNonBlank(key, ERROR_KEY_BLANK);
123         return ConfigUtils.containsKey(mutableKeyValues, key|| (!removedKeys.contains(key&& delegate.containsKey(key));
124     }
125 
126     private static class PrivateMapResourceBundle extends AbstractMapResourceBundle {
127         private final Map<String, Object> map = new LinkedHashMap<>();
128 
129         private PrivateMapResourceBundle(Map<String, Object> map) {
130             this.map.putAll(map);
131             initialize(entries);
132             initializeKeys();
133         }
134 
135         @Override
136         protected void initialize(@Nonnull Map<String, Object> entries) {
137             if (map != null && entries != null) {
138                 entries.putAll(map);
139             }
140         }
141     }
142 }