package act.conf; /*- * #%L * ACT Framework * %% * Copyright (C) 2014 - 2017 ActFramework * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import act.util.DestroyableBase; import org.osgl.exception.ConfigurationException; import org.osgl.exception.UnexpectedNewInstanceException; import org.osgl.util.C; import org.osgl.util.S; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Base class for XxConfig */ public abstract class Config<E extends ConfigKey> extends DestroyableBase { static final String PREFIX = "act."; static final int PREFIX_LEN = PREFIX.length(); protected Map<String, Object> raw; protected Map<ConfigKey, Object> data; /** * Construct a <code>AppConfig</code> with a map. The map is copied to * the original map of the configuration instance * * @param configuration */ public Config(Map<String, ?> configuration) { raw = new HashMap<String, Object>(configuration); data = new HashMap<ConfigKey, Object>(configuration.size()); } public Config() { this((Map) System.getProperties()); } @Override protected void releaseResources() { raw.clear(); data.clear(); super.releaseResources(); } /** * Return configuration by {@link AppConfigKey configuration key} * * @param key * @param <T> * @return the configured item */ public <T> T get(ConfigKey key) { Object o = data.get(key); if (null == o) { o = key.val(raw); if (null != o) { data.put(key, o); } else { data.put(key, NULL); } } if (o == NULL) { return null; } else { return (T) o; } } public Integer getInteger(ConfigKey key) { Object retVal = get(key); if (null == retVal) { return null; } if (retVal instanceof Number) { return ((Number) retVal).intValue(); } return Integer.parseInt(S.string(retVal)); } boolean hasConfiguration(ConfigKey key) { Object o = data.get(key); if (null != o && NULL != o) { return true; } try { o = key.val(raw); if (null == o) { data.put(key, NULL); return false; } return true; } catch (ConfigurationException e) { Throwable t = e.getCause(); if (t instanceof UnexpectedNewInstanceException) { // assume this is caused by certain `.impl` setting which are not a class return true; } // we don't know what it is so just rethrow it throw e; } } /** * Return a configuration value as list * * @param key * @param c * @param <T> * @return the list */ public <T> List<T> getList(AppConfigKey key, Class<T> c) { Object o = data.get(key); if (null == o) { List<T> l = key.implList(key.key(), raw, c); data.put(key, l); return l; } else { return (List) o; } } /** * Look up configuration by a <code>String<code/> key. If the String key * can be converted into {@link AppConfigKey rythm configuration key}, then * it is converted and call to {@link #get(ConfigKey)} method. Otherwise * the original configuration map is used to fetch the value from the string key * * @param key * @param <T> * @return the configured item */ public <T> T get(String key) { if (key.startsWith(PREFIX)) { key = key.substring(PREFIX_LEN); } ConfigKey rk = keyOf(key); if (null != rk) { return get(rk); } else { return AppConfigKey.helper.getConfiguration(key, null, raw); } } public <T> T getIgnoreCase(String key) { if (key.startsWith(PREFIX)) { key = key.substring(PREFIX_LEN); } T t = get(key); if (null != t) { return t; } key = key.toLowerCase(); for (Map.Entry<String, Object> entries : raw.entrySet()) { if (entries.getKey().toLowerCase().equals(key)) { Object o = entries.getValue(); if (o instanceof String) { return (T) AppConfigKey.helper.evaluate(o.toString(), raw); } return (T) o; } else if (entries.getKey().replace('_', '.').equals(key.replace('_', '.'))) { Object o = entries.getValue(); if (o instanceof String) { return (T) AppConfigKey.helper.evaluate(o.toString(), raw); } return (T) o; } } return null; } public Map rawConfiguration() { return raw; } public Map subSet(String prefix) { String prefix2 = "act." + prefix; Map<String, Object> subset = C.newMap(); for (String key : raw.keySet()) { if (key.startsWith(prefix) || key.startsWith(prefix2)) { Object o = data.get(key); if (null == o) { o = raw.get(key); if (null == o) { continue; } if (o instanceof String) { o = AppConfigKey.helper.evaluate(o.toString(), raw); } } if (key.startsWith("act.")) { key = key.substring(4); } if (subset.containsKey(key)) continue; subset.put(key, o); } } return subset; } protected abstract ConfigKey keyOf(String s); private static final Object NULL = new Object(); }