001 /*
002 * SPDX-License-Identifier: Apache-2.0
003 *
004 * Copyright 2008-2017 the original author or authors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package griffon.util;
019
020 import javax.annotation.Nonnull;
021 import javax.annotation.Nullable;
022 import java.util.Enumeration;
023 import java.util.Iterator;
024 import java.util.LinkedHashMap;
025 import java.util.Map;
026 import java.util.ResourceBundle;
027
028 import static griffon.util.ConfigUtils.getConfigValue;
029 import static griffon.util.GriffonNameUtils.requireNonBlank;
030 import static java.util.Objects.requireNonNull;
031
032 /**
033 * @author Andres Almiray
034 * @since 2.0.0
035 */
036 public class ExpandableResourceBundle extends ResourceBundle {
037 private final Map<String, Object> entries = new LinkedHashMap<>();
038
039 @Nonnull
040 public static ResourceBundle wrapResourceBundle(@Nonnull ResourceBundle resourceBundle) {
041 requireNonNull(resourceBundle, "Argument 'resourceBundle' must not be null");
042 if (!(resourceBundle instanceof ExpandableResourceBundle)) {
043 return new ExpandableResourceBundle(resourceBundle);
044 }
045 return resourceBundle;
046 }
047
048 public ExpandableResourceBundle(@Nonnull ResourceBundle delegate) {
049 requireNonNull(delegate, "Argument 'delegate' must not be null");
050 for (String key : delegate.keySet()) {
051 Object value = getConfigValue(delegate, key);
052 processKey(key, entries, value);
053 entries.put(key, value);
054 }
055 }
056
057 @SuppressWarnings("unchecked")
058 private void processKey(@Nonnull String key, @Nonnull Map<String, Object> map, @Nullable Object value) {
059 String[] keys = split(key);
060 if (keys[1] == null) {
061 map.put(keys[0], value);
062 } else {
063 Map<String, Object> m = (Map<String, Object>) map.get(keys[0]);
064 if (m == null) {
065 m = new LinkedHashMap<>();
066 map.put(keys[0], m);
067 }
068 processKey(keys[1], m, value);
069 }
070 }
071
072 @Nonnull
073 private String[] split(@Nonnull String input) {
074 int split = input.indexOf('.');
075 String head = split < 0 ? input : input.substring(0, split);
076 String tail = split > 0 ? input.substring(split + 1) : null;
077 return new String[]{head, tail};
078 }
079
080 @Nullable
081 @Override
082 protected final Object handleGetObject(@Nonnull String key) {
083 return entries.get(requireNonBlank(key, "Argument 'key' must not be blank"));
084 }
085
086 @Nonnull
087 @Override
088 public final Enumeration<String> getKeys() {
089 return new IteratorAsEnumeration<>(entries.keySet().iterator());
090 }
091
092 private static class IteratorAsEnumeration<E> implements Enumeration<E> {
093 private final Iterator<E> iterator;
094
095 public IteratorAsEnumeration(Iterator<E> iterator) {
096 this.iterator = iterator;
097 }
098
099 public boolean hasMoreElements() {
100 return iterator.hasNext();
101 }
102
103 public E nextElement() {
104 return iterator.next();
105 }
106 }
107 }
|