VANILKA
VANILKA

Reputation: 684

Spring profiles: Deny user tu run many profiles from same "group"

I would like to conditioner profiles. For example I have Two groups of profiles: a) DEV, PROD, TEST b) ProfileDB1, ProfileDB2, ProfileDB3

I would like to force that application will be run with one profile of first group, and one profile of second group. But no more. Is it possible ?

Upvotes: 0

Views: 52

Answers (2)

Darren Forsythe
Darren Forsythe

Reputation: 11421

You can add a ApplicationListener that to check when the application is prepared that the profiles are as expected before the rest of the application loads.

public class ProfileValidator implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {

    private static final Logger LOG = LoggerFactory.getLogger(ProfileValidator.class);

    private static final Set<String> DB_PROFILES = new HashSet<>(Arrays.asList("DB1", "DB2", "DB3"));

    private static final Set<String> ENVIRONMENT_PROFILES = new HashSet<>(Arrays.asList("dev", "test"));


    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent applicationEnvironmentPreparedEvent) {
        List<String> activeProfiles = Arrays.asList(applicationEnvironmentPreparedEvent.getEnvironment().getActiveProfiles());

        LOG.info("Validating Allowed Profiles - {}", activeProfiles);

        if (activeProfiles.size() > 1) {
            long count = activeProfiles.stream().filter(profile -> DB_PROFILES.contains(profile) || ENVIRONMENT_PROFILES.contains(profile)).count();

            LOG.debug("Counted {} profiles", count);

            if (count != 0 && activeProfiles.size() - 2 != (activeProfiles.size() - count)) {
                throw new IllegalArgumentException(String.format("Invalid Profiles detected for %s", activeProfiles.toString()));
            }
        }
    }
}

Here's a working example,

https://github.com/DarrenForsythe/spring-profile-validator

Note the spring.factories to register the ApplicationListener. There's also a test class to verify the functionality, and can just start it up with invalid combos or not.

Upvotes: 1

Michiel
Michiel

Reputation: 3510

You could write some kind of an ActiveProfilesVerifier component in which the Environment is injected and the active profiles are verified:

@Component
public class ActiveProfilesVerifier {

    private static final List<String> ENV_PROFILES = Arrays.asList("DEV", "PROD", "TEST");
    private static final List<String> DBASE_PROFILES = Arrays.asList("ProfileDB1", "ProfileDB2", "ProfileDB3");

    private final Environment environment;

    public ActiveProfilesVerifier(Environment environment) {
        this.environment = environment;
    }

    @PostConstruct
    public void verifyProfiles() {
        String[] activeProfiles = environment.getActiveProfiles();

        boolean hasSingleEnvProfile = Arrays.stream(activeProfiles).filter(ENV_PROFILES::contains).count() == 1;
        if (!hasSingleEnvProfile) {
            throw new IllegalArgumentException("Select exactly one environment profile");
        }

        boolean hasSingleDbaseProfile = Arrays.stream(activeProfiles).filter(DBASE_PROFILES::contains).count() == 1;
        if (!hasSingleDbaseProfile) {
            throw new IllegalArgumentException("Select exactly one database profile");
        }
    }
}

Upvotes: 1

Related Questions