PatternSubtreeConfigurationWrapper.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
- package org.apache.commons.configuration2;
- import java.io.IOException;
- import java.io.Reader;
- import java.io.Writer;
- import java.math.BigDecimal;
- import java.math.BigInteger;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Objects;
- import java.util.Properties;
- import org.apache.commons.configuration2.event.Event;
- import org.apache.commons.configuration2.event.EventListener;
- import org.apache.commons.configuration2.event.EventType;
- import org.apache.commons.configuration2.ex.ConfigurationException;
- import org.apache.commons.configuration2.io.FileBased;
- import org.apache.commons.configuration2.tree.ExpressionEngine;
- import org.apache.commons.configuration2.tree.ImmutableNode;
- /**
- * Wraps a BaseHierarchicalConfiguration and allows subtrees to be accessed via a configured path with replaceable
- * tokens derived from the ConfigurationInterpolator. When used with injection frameworks such as Spring it allows
- * components to be injected with subtrees of the configuration.
- *
- * @since 1.6
- */
- public class PatternSubtreeConfigurationWrapper extends BaseHierarchicalConfiguration implements FileBasedConfiguration {
- /** The wrapped configuration */
- private final HierarchicalConfiguration<ImmutableNode> config;
- /** The path to the subtree */
- private final String path;
- /** True if the path ends with '/', false otherwise */
- private final boolean trailing;
- /** True if the constructor has finished */
- private final boolean init;
- /**
- * Constructor
- *
- * @param config The Configuration to be wrapped.
- * @param path The base path pattern.
- */
- public PatternSubtreeConfigurationWrapper(final HierarchicalConfiguration<ImmutableNode> config, final String path) {
- this.config = Objects.requireNonNull(config, "config");
- this.path = path;
- this.trailing = path.endsWith("/");
- this.init = true;
- }
- @Override
- public <T extends Event> void addEventListener(final EventType<T> eventType, final EventListener<? super T> listener) {
- getConfig().addEventListener(eventType, listener);
- }
- @Override
- protected void addNodesInternal(final String key, final Collection<? extends ImmutableNode> nodes) {
- getConfig().addNodes(key, nodes);
- }
- @Override
- protected void addPropertyInternal(final String key, final Object value) {
- config.addProperty(makePath(key), value);
- }
- @Override
- public void clearErrorListeners() {
- getConfig().clearErrorListeners();
- }
- @Override
- public void clearEventListeners() {
- getConfig().clearEventListeners();
- }
- @Override
- protected void clearInternal() {
- getConfig().clear();
- }
- @Override
- protected void clearPropertyDirect(final String key) {
- config.clearProperty(makePath(key));
- }
- @Override
- protected Object clearTreeInternal(final String key) {
- config.clearTree(makePath(key));
- return Collections.emptyList();
- }
- @Override
- public HierarchicalConfiguration<ImmutableNode> configurationAt(final String key) {
- return config.configurationAt(makePath(key));
- }
- @Override
- public HierarchicalConfiguration<ImmutableNode> configurationAt(final String key, final boolean supportUpdates) {
- return config.configurationAt(makePath(key), supportUpdates);
- }
- @Override
- public List<HierarchicalConfiguration<ImmutableNode>> configurationsAt(final String key) {
- return config.configurationsAt(makePath(key));
- }
- @Override
- protected boolean containsKeyInternal(final String key) {
- return config.containsKey(makePath(key));
- }
- /**
- * Tests whether this configuration contains one or more matches to this value. This operation stops at first
- * match but may be more expensive than the containsKey method.
- * @since 2.11.0
- */
- @Override
- protected boolean containsValueInternal(final Object value) {
- return config.containsValue(value);
- }
- /**
- * Returns the wrapped configuration as a {@code FileBased} object. If this cast is not possible, an exception is
- * thrown.
- *
- * @return the wrapped configuration as {@code FileBased}
- * @throws ConfigurationException if the wrapped configuration does not implement {@code FileBased}
- */
- private FileBased fetchFileBased() throws ConfigurationException {
- if (!(config instanceof FileBased)) {
- throw new ConfigurationException("Wrapped configuration does not implement FileBased!" + " No I/O operations are supported.");
- }
- return (FileBased) config;
- }
- @Override
- public BigDecimal getBigDecimal(final String key) {
- return config.getBigDecimal(makePath(key));
- }
- @Override
- public BigDecimal getBigDecimal(final String key, final BigDecimal defaultValue) {
- return config.getBigDecimal(makePath(key), defaultValue);
- }
- @Override
- public BigInteger getBigInteger(final String key) {
- return config.getBigInteger(makePath(key));
- }
- @Override
- public BigInteger getBigInteger(final String key, final BigInteger defaultValue) {
- return config.getBigInteger(makePath(key), defaultValue);
- }
- @Override
- public boolean getBoolean(final String key) {
- return config.getBoolean(makePath(key));
- }
- @Override
- public boolean getBoolean(final String key, final boolean defaultValue) {
- return config.getBoolean(makePath(key), defaultValue);
- }
- @Override
- public Boolean getBoolean(final String key, final Boolean defaultValue) {
- return config.getBoolean(makePath(key), defaultValue);
- }
- @Override
- public byte getByte(final String key) {
- return config.getByte(makePath(key));
- }
- @Override
- public byte getByte(final String key, final byte defaultValue) {
- return config.getByte(makePath(key), defaultValue);
- }
- @Override
- public Byte getByte(final String key, final Byte defaultValue) {
- return config.getByte(makePath(key), defaultValue);
- }
- private BaseHierarchicalConfiguration getConfig() {
- return (BaseHierarchicalConfiguration) config.configurationAt(makePath());
- }
- @Override
- public double getDouble(final String key) {
- return config.getDouble(makePath(key));
- }
- @Override
- public double getDouble(final String key, final double defaultValue) {
- return config.getDouble(makePath(key), defaultValue);
- }
- @Override
- public Double getDouble(final String key, final Double defaultValue) {
- return config.getDouble(makePath(key), defaultValue);
- }
- @Override
- public <T extends Event> Collection<EventListener<? super T>> getEventListeners(final EventType<T> eventType) {
- return getConfig().getEventListeners(eventType);
- }
- @Override
- public ExpressionEngine getExpressionEngine() {
- return config.getExpressionEngine();
- }
- @Override
- public float getFloat(final String key) {
- return config.getFloat(makePath(key));
- }
- @Override
- public float getFloat(final String key, final float defaultValue) {
- return config.getFloat(makePath(key), defaultValue);
- }
- @Override
- public Float getFloat(final String key, final Float defaultValue) {
- return config.getFloat(makePath(key), defaultValue);
- }
- @Override
- public int getInt(final String key) {
- return config.getInt(makePath(key));
- }
- @Override
- public int getInt(final String key, final int defaultValue) {
- return config.getInt(makePath(key), defaultValue);
- }
- @Override
- public Integer getInteger(final String key, final Integer defaultValue) {
- return config.getInteger(makePath(key), defaultValue);
- }
- @Override
- protected Iterator<String> getKeysInternal() {
- return config.getKeys(makePath());
- }
- @Override
- protected Iterator<String> getKeysInternal(final String prefix) {
- return config.getKeys(makePath(prefix));
- }
- @Override
- public List<Object> getList(final String key) {
- return config.getList(makePath(key));
- }
- @Override
- public List<Object> getList(final String key, final List<?> defaultValue) {
- return config.getList(makePath(key), defaultValue);
- }
- @Override
- public long getLong(final String key) {
- return config.getLong(makePath(key));
- }
- @Override
- public long getLong(final String key, final long defaultValue) {
- return config.getLong(makePath(key), defaultValue);
- }
- @Override
- public Long getLong(final String key, final Long defaultValue) {
- return config.getLong(makePath(key), defaultValue);
- }
- @Override
- protected int getMaxIndexInternal(final String key) {
- return config.getMaxIndex(makePath(key));
- }
- @Override
- public Properties getProperties(final String key) {
- return config.getProperties(makePath(key));
- }
- @Override
- protected Object getPropertyInternal(final String key) {
- return config.getProperty(makePath(key));
- }
- @Override
- public short getShort(final String key) {
- return config.getShort(makePath(key));
- }
- @Override
- public short getShort(final String key, final short defaultValue) {
- return config.getShort(makePath(key), defaultValue);
- }
- @Override
- public Short getShort(final String key, final Short defaultValue) {
- return config.getShort(makePath(key), defaultValue);
- }
- @Override
- public String getString(final String key) {
- return config.getString(makePath(key));
- }
- @Override
- public String getString(final String key, final String defaultValue) {
- return config.getString(makePath(key), defaultValue);
- }
- @Override
- public String[] getStringArray(final String key) {
- return config.getStringArray(makePath(key));
- }
- @Override
- public Configuration interpolatedConfiguration() {
- return getConfig().interpolatedConfiguration();
- }
- @Override
- protected boolean isEmptyInternal() {
- return getConfig().isEmpty();
- }
- private String makePath() {
- final String pathPattern = trailing ? path.substring(0, path.length() - 1) : path;
- return substitute(pathPattern);
- }
- /*
- * Resolve the root expression and then add the item being retrieved. Insert a separator character as required.
- */
- private String makePath(final String item) {
- final String pathPattern;
- if ((item.isEmpty() || item.startsWith("/")) && trailing) {
- pathPattern = path.substring(0, path.length() - 1);
- } else if (!item.startsWith("/") || !trailing) {
- pathPattern = path + "/";
- } else {
- pathPattern = path;
- }
- return substitute(pathPattern) + item;
- }
- @Override
- public void read(final Reader reader) throws ConfigurationException, IOException {
- fetchFileBased().read(reader);
- }
- @Override
- public <T extends Event> boolean removeEventListener(final EventType<T> eventType, final EventListener<? super T> listener) {
- return getConfig().removeEventListener(eventType, listener);
- }
- @Override
- public void setExpressionEngine(final ExpressionEngine expressionEngine) {
- if (init) {
- config.setExpressionEngine(expressionEngine);
- } else {
- super.setExpressionEngine(expressionEngine);
- }
- }
- @Override
- protected void setPropertyInternal(final String key, final Object value) {
- getConfig().setProperty(key, value);
- }
- @Override
- public Configuration subset(final String prefix) {
- return getConfig().subset(prefix);
- }
- /**
- * Uses this configuration's {@code ConfigurationInterpolator} to perform variable substitution on the given pattern
- * string.
- *
- * @param pattern the pattern string
- * @return the string with variables replaced
- */
- private String substitute(final String pattern) {
- return Objects.toString(getInterpolator().interpolate(pattern), null);
- }
- @Override
- public void write(final Writer writer) throws ConfigurationException, IOException {
- fetchFileBased().write(writer);
- }
- }