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             return mutableKeyValues.remove(key);
067         else if (delegate.containsKey(key)) {
068             removedKeys.add(key);
069             return delegate.get(key);
070         }
071         return null;
072     }
073 
074     @Nonnull
075     @Override
076     public Map<String, Object> asFlatMap() {
077         Map<String, Object> flatMap = new LinkedHashMap<>(delegate.asFlatMap());
078         flatMap.putAll(mutableKeyValues);
079         for (String removedKey : removedKeys) {
080             flatMap.remove(removedKey);
081         }
082         return unmodifiableMap(flatMap);
083     }
084 
085     @Nonnull
086     @Override
087     public ResourceBundle asResourceBundle() {
088         return new CompositeResourceBundle(asList(new PrivateMapResourceBundle(asFlatMap()), delegate.asResourceBundle()));
089     }
090 
091     @Nullable
092     @Override
093     public Object get(@Nonnull String key) {
094         requireNonBlank(key, ERROR_KEY_BLANK);
095         try {
096             return getConfigValue(mutableKeyValues, key);
097         catch (MissingResourceException mre) {
098             if (removedKeys.contains(key)) {
099                 return null;
100             }
101             return super.get(key);
102         }
103     }
104 
105     @Override
106     public boolean containsKey(@Nonnull String key) {
107         requireNonBlank(key, ERROR_KEY_BLANK);
108         return ConfigUtils.containsKey(mutableKeyValues, key|| (!removedKeys.contains(key&& delegate.containsKey(key));
109     }
110 
111     private static class PrivateMapResourceBundle extends AbstractMapResourceBundle {
112         private final Map<String, Object> map = new LinkedHashMap<>();
113 
114         private PrivateMapResourceBundle(Map<String, Object> map) {
115             this.map.putAll(map);
116             initialize(entries);
117             initializeKeys();
118         }
119 
120         @Override
121         protected void initialize(@Nonnull Map<String, Object> entries) {
122             if (map != null && entries != null) {
123                 entries.putAll(map);
124             }
125         }
126     }
127 }