001 /*
002 * Copyright 2008-2017 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 < 0 ? input : input.substring(0, split);
074 String tail = split > 0 ? input.substring(split + 1) : null;
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 }
|