All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.obvj.confectory.Configuration Maven / Gradle / Ivy

/*
 * Copyright 2021 obvj.net
 *
 * 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.
 */

package net.obvj.confectory;

import java.util.Objects;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import net.obvj.confectory.helper.ConfigurationHelper;
import net.obvj.confectory.helper.NullConfigurationHelper;
import net.obvj.confectory.mapper.Mapper;
import net.obvj.confectory.source.Source;

/**
 * An object that contains configuration data from a specific source, as well as related
 * metadata.
 * 

* A {@code Configuration} may also be defined as a combination of a {@link Source} and a * {@link Mapper}, producing either a properties list, a JSON object, or a user-defined * bean. *

* Each {@code Configuration} may be assigned a namespace and precedence number, which * determines an order of importance. So, once stored in a common configuration container, * the object with the highest precedence value will be chosen first, taking precedence * over the other ones in the same namespace. *

* A {@code Configuration} object is eager by default, that is, the resource will * be loaded directly during {@code build()} time. Optionally, a {@code Configuration} may * be created with the lazy flag, indicating that the resource shall not be loaded * until really needed. *

* A {@code Configuration} may also be marked as optional, indicating that the * configuration shall be loaded quietly, that is, an "empty" {@code Configuration} object * will be instantiated even if the resource cannot be loaded (not default behavior). *

* IMPORTANT: Use a {@link ConfigurationBuilder} to create a * {@code Configuration} object. A builder instance can be retrieved by calling * {@link Configuration#builder()}. For example: * *

* *
 * {@code Configuration config = Configuration.builder()}
 * {@code         .source(new ClasspathFileSource<>("my.properties"))}
 * {@code         .mapper(new PropertiesMapper())}
 * {@code         .namespace("default")}
 * {@code         .precedence(10)}
 * {@code         .build();}
 * 
* *
* * @param the target configuration type * * @see Source * @see Mapper * @see ConfigurationBuilder * * @author oswaldo.bapvic.jr (Oswaldo Junior) * @since 0.1.0 */ public final class Configuration implements ConfigurationDataRetriever, ConfigurationMetadataRetriever { private final String namespace; private final int precedence; private final Source source; private final Mapper mapper; private final boolean optional; private final boolean lazy; private ConfigurationDataRetriever service; /** * Builds a new {@code Configuration} from the specified {@link ConfigurationBuilder}. * * @param builder the {@link ConfigurationBuilder} to be built */ protected Configuration(ConfigurationBuilder builder) { this.namespace = builder.getNamespace(); this.precedence = builder.getPrecedence(); this.source = builder.getSource(); this.mapper = builder.getMapper(); this.optional = builder.isOptional(); this.lazy = builder.isLazy(); if (!lazy) { getService(); } } /** * Creates a new configuration builder. * * @param the target configuration type * @return a new {@link ConfigurationBuilder} */ public static ConfigurationBuilder builder() { return new ConfigurationBuilder<>(); } @Override public String getNamespace() { return namespace; } @Override public int getPrecedence() { return precedence; } @Override public Source getSource() { return source; } @Override public Mapper getMapper() { return mapper; } @Override public boolean isOptional() { return optional; } @Override public boolean isLazy() { return lazy; } @Override public T getBean() { return getService().getBean(); } @Override public Boolean getBoolean(String key) { return getService().getBoolean(key); } @Override public Integer getInteger(String key) { return getService().getInteger(key); } @Override public Long getLong(String key) { return getService().getLong(key); } @Override public Double getDouble(String key) { return getService().getDouble(key); } @Override public String getString(String key) { return getService().getString(key); } @Override public int hashCode() { return Objects.hash(namespace, source); } /** * Indicates whether some other object is "equal to" this one. *

* Two {@code Configuration} objects can be considered equal if both share the same * {@code namespace} and {@code Source}. * * @param other the other object with which to compare * * @return {@code true} if this object is the same as the one specified in the argument; * {@code false} otherwise. */ @Override public boolean equals(Object other) { if (this == other) { return true; } if (other == null) { return false; } if (getClass() != other.getClass()) { return false; } Configuration otherConfiguration = (Configuration) other; return Objects.equals(namespace, otherConfiguration.namespace) && Objects.equals(source, otherConfiguration.source); } @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.JSON_STYLE).append("namespace", namespace) .append("precedence", precedence).append("source", source).toString(); } @Override public Boolean getMandatoryBoolean(String key) { return getService().getMandatoryBoolean(key); } @Override public Integer getMandatoryInteger(String key) { return getService().getMandatoryInteger(key); } @Override public Long getMandatoryLong(String key) { return getService().getMandatoryLong(key); } @Override public Double getMandatoryDouble(String key) { return getService().getMandatoryDouble(key); } @Override public String getMandatoryString(String key) { return getService().getMandatoryString(key); } /** * @return the actual implementation (the Service part in the Proxy Design Pattern) * @since 0.4.0 */ private ConfigurationDataRetriever getService() { if (service == null) { service = new ConfigurationService<>(source, mapper, optional); } return service; } } /** * Actual implementation (the Service part in the Proxy Design Pattern). * * @param the target configuration type * * @author oswaldo.bapvic.jr (Oswaldo Junior) * @since 0.4.0 */ final class ConfigurationService implements ConfigurationDataRetriever { private final T bean; private final ConfigurationHelper helper; ConfigurationService(Source source, Mapper mapper, boolean optional) { this.bean = source.load(mapper, optional); this.helper = getConfigurationHelper(bean, mapper); } static ConfigurationHelper getConfigurationHelper(T bean, Mapper mapper) { return bean != null ? mapper.configurationHelper(bean) : new NullConfigurationHelper<>(); } @Override public T getBean() { return bean; } @Override public Boolean getBoolean(String key) { return helper.getBoolean(key); } @Override public Integer getInteger(String key) { return helper.getInteger(key); } @Override public Long getLong(String key) { return helper.getLong(key); } @Override public Double getDouble(String key) { return helper.getDouble(key); } @Override public String getString(String key) { return helper.getString(key); } @Override public Boolean getMandatoryBoolean(String key) { return helper.getMandatoryBoolean(key); } @Override public Integer getMandatoryInteger(String key) { return helper.getMandatoryInteger(key); } @Override public Long getMandatoryLong(String key) { return helper.getMandatoryLong(key); } @Override public Double getMandatoryDouble(String key) { return helper.getMandatoryDouble(key); } @Override public String getMandatoryString(String key) { return helper.getMandatoryString(key); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy