ExpandableResourceBundle.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 griffon.util;
017 
018 import javax.annotation.Nonnull;
019 import javax.annotation.Nullable;
020 import java.util.Enumeration;
021 import java.util.Iterator;
022 import java.util.LinkedHashMap;
023 import java.util.Map;
024 import java.util.ResourceBundle;
025 
026 import static griffon.util.ConfigUtils.getConfigValue;
027 import static griffon.util.GriffonNameUtils.requireNonBlank;
028 import static java.util.Objects.requireNonNull;
029 
030 /**
031  @author Andres Almiray
032  @since 2.0.0
033  */
034 public class ExpandableResourceBundle extends ResourceBundle {
035     private final Map<String, Object> entries = new LinkedHashMap<>();
036 
037     @Nonnull
038     public static ResourceBundle wrapResourceBundle(@Nonnull ResourceBundle resourceBundle) {
039         requireNonNull(resourceBundle, "Argument 'resourceBundle' must not be null");
040         if (!(resourceBundle instanceof ExpandableResourceBundle)) {
041             return new ExpandableResourceBundle(resourceBundle);
042         }
043         return resourceBundle;
044     }
045 
046     public ExpandableResourceBundle(@Nonnull ResourceBundle delegate) {
047         requireNonNull(delegate, "Argument 'delegate' must not be null");
048         for (String key : delegate.keySet()) {
049             Object value = getConfigValue(delegate, key);
050             processKey(key, entries, value);
051             entries.put(key, value);
052         }
053     }
054 
055     @SuppressWarnings("unchecked")
056     private void processKey(@Nonnull String key, @Nonnull Map<String, Object> map, @Nullable Object value) {
057         String[] keys = split(key);
058         if (keys[1== null) {
059             map.put(keys[0], value);
060         else {
061             Map<String, Object> m = (Map<String, Object>map.get(keys[0]);
062             if (m == null) {
063                 m = new LinkedHashMap<>();
064                 map.put(keys[0], m);
065             }
066             processKey(keys[1], m, value);
067         }
068     }
069 
070     @Nonnull
071     private String[] split(@Nonnull String input) {
072         int split = input.indexOf(".");
073         String head = split < ? input : input.substring(0, split);
074         String tail = split > ? input.substring(split + 1null;
075         return new String[]{head, tail};
076     }
077 
078     @Nullable
079     @Override
080     protected final Object handleGetObject(@Nonnull String key) {
081         return entries.get(requireNonBlank(key, "Argument 'key' must not be blank"));
082     }
083 
084     @Nonnull
085     @Override
086     public final Enumeration<String> getKeys() {
087         return new IteratorAsEnumeration<>(entries.keySet().iterator());
088     }
089 
090     private static class IteratorAsEnumeration<E> implements Enumeration<E> {
091         private final Iterator<E> iterator;
092 
093         public IteratorAsEnumeration(Iterator<E> iterator) {
094             this.iterator = iterator;
095         }
096 
097         public boolean hasMoreElements() {
098             return iterator.hasNext();
099         }
100 
101         public E nextElement() {
102             return iterator.next();
103         }
104     }
105 }