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

com.aspectran.core.context.env.EnvironmentProfiles Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2008-2025 The Aspectran Project
 *
 * 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 com.aspectran.core.context.env;

import com.aspectran.utils.Assert;
import com.aspectran.utils.StringUtils;
import com.aspectran.utils.SystemUtils;
import com.aspectran.utils.annotation.jsr305.NonNull;
import com.aspectran.utils.annotation.jsr305.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.LinkedHashSet;
import java.util.Set;

/**
 * Environment profiles provide baseline information for applications to recognize
 * different execution environments. e.g. development, test, production etc.
 */
public class EnvironmentProfiles {

    private static final Logger logger = LoggerFactory.getLogger(EnvironmentProfiles.class);

    /**
     * Name of property to set to specify the base profiles: {@value}. Value may be comma-delimited.
     * If there is a system property that contains a context name starting with this property name,
     * that takes priority.
     */
    public static final String BASE_PROFILES_PROPERTY_NAME = "aspectran.profiles.base";

    /**
     * Name of property to set to specify profiles active by default: {@value}. Value may
     * be comma-delimited.
     */
    public static final String DEFAULT_PROFILES_PROPERTY_NAME = "aspectran.profiles.default";

    /**
     * Name of property to set to specify active profiles: {@value}. Value may be comma-delimited.
     */
    public static final String ACTIVE_PROFILES_PROPERTY_NAME = "aspectran.profiles.active";

    private final Set baseProfiles = new LinkedHashSet<>();

    private final Set defaultProfiles = new LinkedHashSet<>();

    private final Set activeProfiles = new LinkedHashSet<>();

    public EnvironmentProfiles(String contextName) {
        String[] profiles = doGetBaseProfilesProperty(contextName);
        if (profiles != null) {
            setBaseProfiles(profiles);
        }
    }

    public boolean hasBaseProfiles() {
        return !baseProfiles.isEmpty();
    }

    @NonNull
    public String[] getBaseProfiles() {
        return StringUtils.toStringArray(baseProfiles);
    }

    public void setBaseProfiles(String... profiles) {
        Assert.notNull(profiles, "profiles must not be null");
        synchronized (baseProfiles) {
            baseProfiles.clear();
            logger.info("Base profiles [{}]", StringUtils.joinWithCommas(profiles));
            for (String profile : profiles) {
                validateProfile(profile);
                baseProfiles.add(profile);
            }
        }
    }

    private String[] doGetBaseProfilesProperty(String contextName) {
        String propertyName;
        if (contextName == null) {
            propertyName = BASE_PROFILES_PROPERTY_NAME;
        } else {
            propertyName = BASE_PROFILES_PROPERTY_NAME + "." + contextName;
        }
        return getProfilesFromSystemProperty(propertyName);
    }

    @NonNull
    public String[] getDefaultProfiles() {
        return StringUtils.toStringArray(doGetDefaultProfiles());
    }

    /**
     * Returns the set of default profiles explicitly set via
     * {@link #setDefaultProfiles(String...)}, then check for the presence of the
     * {@value #DEFAULT_PROFILES_PROPERTY_NAME} property and assign its value (if any)
     * to the set of default profiles.
     */
    private Set doGetDefaultProfiles() {
        synchronized (defaultProfiles) {
            if (defaultProfiles.isEmpty()) {
                String[] profiles = doGetDefaultProfilesProperty();
                if (profiles != null) {
                    setDefaultProfiles(profiles);
                }
            }
            return defaultProfiles;
        }
    }

    private String[] doGetDefaultProfilesProperty() {
        return getProfilesFromSystemProperty(DEFAULT_PROFILES_PROPERTY_NAME);
    }

    /**
     * Specify the set of profiles to be made active by default if no other profiles
     * are explicitly made active through {@link #setActiveProfiles}.
     * 

Calling this method removes overrides any reserved default profiles * that may have been added during construction of the environment.

* @param profiles the set of profiles to be made active by default */ public void setDefaultProfiles(String... profiles) { Assert.notNull(profiles, "profiles must not be null"); logger.info("Default profiles [{}]", StringUtils.joinWithCommas(profiles)); synchronized (defaultProfiles) { defaultProfiles.clear(); for (String profile : profiles) { validateProfile(profile); defaultProfiles.add(profile); } } } @NonNull public String[] getActiveProfiles() { return StringUtils.toStringArray(doGetActiveProfiles()); } /** * Returns the set of active profiles as explicitly set through * {@link #setActiveProfiles} or if the current set of active profiles * is empty, check for the presence of the {@value #ACTIVE_PROFILES_PROPERTY_NAME} * property and assign its value to the set of active profiles. * @see #getActiveProfiles() * @see #ACTIVE_PROFILES_PROPERTY_NAME */ private Set doGetActiveProfiles() { synchronized (activeProfiles) { if (activeProfiles.isEmpty()) { String[] profiles = doGetActiveProfilesProperty(); if (profiles != null) { setActiveProfiles(profiles); } } return activeProfiles; } } private String[] doGetActiveProfilesProperty() { return getProfilesFromSystemProperty(ACTIVE_PROFILES_PROPERTY_NAME); } /** * Specify the set of profiles active for this {@code Environment}. * Profiles are evaluated during the ActivityContext configuration to determine * whether configuration settings or rules should be registered. *

Any existing active profiles will be replaced with the given arguments; call * with zero arguments to clear the current set of active profiles.

* @param profiles the set of profiles active * @see #setDefaultProfiles * @throws IllegalArgumentException if any profile is null, empty or whitespace-only */ public void setActiveProfiles(String... profiles) { Assert.notNull(profiles, "profiles must not be null"); logger.info("Activating profiles [{}]", StringUtils.joinWithCommas(profiles)); synchronized (activeProfiles) { activeProfiles.clear(); for (String profile : profiles) { validateProfile(profile); activeProfiles.add(profile); } } } public void addActiveProfile(String profile) { logger.info("Activating profile '{}'", profile); validateProfile(profile); doGetActiveProfiles(); synchronized (activeProfiles) { activeProfiles.add(profile); } } /** * Determine whether one of the given profile expressions matches the * {@linkplain #getActiveProfiles() active profiles} — or in the case * of no explicit active profiles, whether one of the given profile expressions * matches the {@linkplain #getDefaultProfiles() default profiles}. *

Profile expressions allow for complex, boolean profile logic to be * expressed — for example {@code "p1 & p2"}, {@code "(p1 & p2) | p3"}, * etc. See {@link Profiles#of(String)} for details on the supported * expression syntax. *

This method is a convenient shortcut for * {@code env.acceptsProfiles(Profiles.of(profileExpressions))}. * @since 7.5.0 * @see Profiles#of(String) * @see #acceptsProfiles(Profiles) */ public boolean matchesProfiles(String profileExpression) { return acceptsProfiles(Profiles.of(profileExpression)); } /** * Determine whether the given {@link Profiles} predicate matches the * {@linkplain #getActiveProfiles() active profiles} — or in the case * of no explicit active profiles, whether the given {@code Profiles} predicate * matches the {@linkplain #getDefaultProfiles() default profiles}. *

If you wish provide profile expressions directly as strings, use * {@link #matchesProfiles(String)} instead. * @since 7.5.0 * @see #matchesProfiles(String) * @see Profiles#of(String) */ public boolean acceptsProfiles(Profiles profiles) { return (profiles == null || profiles.matches(this::isProfileActive)); } /** * Determine whether one or more of the given profiles is active — or * in the case of no explicit {@linkplain #getActiveProfiles() active profiles}, * whether one or more of the given profiles is included in the set of * {@linkplain #getDefaultProfiles() default profiles}. *

If a profile begins with '!' the logic is inverted, meaning this method * will return {@code true} if the given profile is not active. For * example, {@code env.acceptsProfiles("p1", "!p2")} will return {@code true} * if profile 'p1' is active or 'p2' is not active. * @throws IllegalArgumentException if called with a {@code null} array, an * empty array, zero arguments or if any profile is {@code null}, empty, or * whitespace only * @see #getActiveProfiles * @see #getDefaultProfiles * @see #matchesProfiles(String) * @see #acceptsProfiles(Profiles) */ public boolean acceptsProfiles(String... profiles) { if (profiles == null || profiles.length == 0) { return true; } for (String profile : profiles) { if (StringUtils.hasLength(profile) && profile.charAt(0) == '!') { if (!isProfileActive(profile.substring(1))) { return true; } } else { if (isProfileActive(profile)) { return true; } } } return false; } /** * Returns whether the given profile is active, or if active profiles are empty * whether the profile should be active by default. * @throws IllegalArgumentException per {@link #validateProfile(String)} */ private boolean isProfileActive(String profile) { validateProfile(profile); if (baseProfiles.contains(profile)) { return true; } Set currentActiveProfiles = doGetActiveProfiles(); return (currentActiveProfiles.contains(profile) || (currentActiveProfiles.isEmpty() && doGetDefaultProfiles().contains(profile))); } /** * Validate the given profile, called internally prior to adding to the set of * active or default profiles. *

Subclasses may override to impose further restrictions on profile syntax.

* @param profile the given profile * @throws IllegalArgumentException if the profile is null, empty, whitespace-only or * begins with the profile NOT operator (!) * @see #acceptsProfiles * @see #setDefaultProfiles */ private void validateProfile(String profile) { if (!StringUtils.hasText(profile)) { throw new IllegalArgumentException("Invalid profile [" + profile + "]; must contain text"); } if (profile.charAt(0) == '!') { throw new IllegalArgumentException("Invalid profile [" + profile + "]; must not begin with ! operator"); } } @Nullable private String[] getProfilesFromSystemProperty(String propName) { String profilesProp = SystemUtils.getProperty(propName); if (profilesProp != null) { String[] profiles = StringUtils.splitWithComma(profilesProp); if (profiles.length > 0) { return profiles; } } return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy