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

io.micronaut.context.RequiresCondition Maven / Gradle / Ivy

There is a newer version: 4.7.5
Show newest version
/*
 * Copyright 2017-2020 original authors
 *
 * 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
 *
 * https://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 io.micronaut.context;

import groovy.lang.GroovySystem;
import io.micronaut.context.annotation.Requires;
import io.micronaut.context.condition.Condition;
import io.micronaut.context.condition.ConditionContext;
import io.micronaut.context.condition.OperatingSystem;
import io.micronaut.context.condition.TrueCondition;
import io.micronaut.context.env.CachedEnvironment;
import io.micronaut.context.env.Environment;
import io.micronaut.core.annotation.AnnotationClassValue;
import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.AnnotationMetadataProvider;
import io.micronaut.core.annotation.AnnotationValue;
import io.micronaut.core.convert.ConversionContext;
import io.micronaut.core.io.ResourceLoader;
import io.micronaut.core.io.ResourceResolver;
import io.micronaut.core.io.file.FileSystemResourceLoader;
import io.micronaut.core.io.scan.ClassPathResourceLoader;
import io.micronaut.core.reflect.ClassUtils;
import io.micronaut.core.reflect.InstantiationUtils;
import io.micronaut.core.reflect.ReflectionUtils;
import io.micronaut.core.type.Argument;
import io.micronaut.core.util.ArrayUtils;
import io.micronaut.core.util.StringUtils;
import io.micronaut.core.value.PropertyResolver;
import io.micronaut.core.version.SemanticVersion;
import io.micronaut.core.version.VersionUtils;
import io.micronaut.inject.BeanConfiguration;
import io.micronaut.inject.BeanDefinition;
import io.micronaut.inject.BeanDefinitionReference;
import kotlin.KotlinVersion;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.*;

/**
 * An abstract {@link Condition} implementation that is based on the presence
 * of {@link Requires} annotation.
 *
 * @author graemerocher
 * @since 1.0.0
 */
public class RequiresCondition implements Condition {

    public static final String MEMBER_PROPERTY = "property";
    public static final String MEMBER_NOT_EQUALS = "notEquals";
    public static final String MEMBER_DEFAULT_VALUE = "defaultValue";
    public static final String MEMBER_PATTERN = "pattern";
    public static final String MEMBER_MISSING_PROPERTY = "missingProperty";
    public static final String MEMBER_ENV = "env";
    public static final String MEMBER_NOT_ENV = "notEnv";
    public static final String MEMBER_CONDITION = "condition";
    public static final String MEMBER_SDK = "sdk";
    public static final String MEMBER_VERSION = "version";
    public static final String MEMBER_MISSING_CLASSES = "missing";
    public static final String MEMBER_RESOURCES = "resources";
    public static final String MEMBER_CONFIGURATION = "configuration";
    public static final String MEMBER_CLASSES = "classes";
    public static final String MEMBER_ENTITIES = "entities";
    public static final String MEMBER_BEANS = "beans";
    public static final String MEMBER_MISSING_BEANS = "missingBeans";
    public static final String MEMBER_OS = "os";
    public static final String MEMBER_NOT_OS = "notOs";
    public static final String MEMBER_BEAN = "bean";
    public static final String MEMBER_BEAN_PROPERTY = "beanProperty";

    private final AnnotationMetadata annotationMetadata;

    /**
     * @param annotationMetadata The annotation metadata
     */
    public RequiresCondition(AnnotationMetadata annotationMetadata) {
        this.annotationMetadata = annotationMetadata;
    }

    @Override
    public boolean matches(ConditionContext context) {
        List> requirements = annotationMetadata.getAnnotationValuesByType(Requires.class);
        if (requirements.isEmpty()) {
            return true;
        }
        AnnotationMetadataProvider component = context.getComponent();
        boolean isBeanReference = component instanceof BeanDefinitionReference;

        if (component instanceof AbstractInitializableBeanDefinitionAndReference) {
            for (AnnotationValue requirement : requirements) {
                processPreStartRequirements(context, requirement);
                if (context.isFailing()) {
                    return false;
                }
                processPostStartRequirements(context, requirement);
                if (context.isFailing()) {
                    return false;
                }
            }
            return true;
        }

        // here we use AnnotationMetadata to avoid loading the classes referenced in the annotations directly
        if (isBeanReference) {
            for (AnnotationValue requirement : requirements) {
                // if annotation value has evaluated expressions, postpone
                // decision until the bean is loaded
                if (requirement.hasEvaluatedExpressions()) {
                    continue;
                }

                processPreStartRequirements(context, requirement);
                if (context.isFailing()) {
                    return false;
                }
            }
        } else {
            for (AnnotationValue requires : requirements) {
                processPostStartRequirements(context, requires);
                if (context.isFailing()) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * @param context  The condition context
     * @param requirements The requires
     * @return Whether matches the condition
     */
    protected boolean matchesConfiguration(ConditionContext context, AnnotationValue requirements) {
        if (requirements.contains(MEMBER_CONFIGURATION)) {
            String configurationName = requirements.stringValue(MEMBER_CONFIGURATION).orElse(null);
            if (StringUtils.isEmpty(configurationName)) {
                return true;
            }

            BeanContext beanContext = context.getBeanContext();
            String minimumVersion = requirements.stringValue(MEMBER_VERSION).orElse(null);
            Optional beanConfiguration = beanContext.findBeanConfiguration(configurationName);
            if (beanConfiguration.isEmpty()) {
                context.fail("Required configuration [" + configurationName + "] is not active");
                return false;
            } else {
                String version = beanConfiguration.get().getVersion();
                if (version != null && StringUtils.isNotEmpty(minimumVersion)) {
                    boolean result = SemanticVersion.isAtLeast(version, minimumVersion);
                    context.fail("Required configuration [" + configurationName + "] version requirements not met. Required: " + minimumVersion + ", Current: " + version);
                    return result;
                } else {
                    return true;
                }
            }
        } else {
            return true;
        }
    }

    /**
     * This method will process requirements for a {@link BeanDefinitionReference} that has not yet been loaded. Unlike {@link #processPostStartRequirements(ConditionContext, AnnotationValue)}
     * this method is executed prior to the bean being loaded and processes requirements that do not require all the beans to be loaded.
     */
    private void processPreStartRequirements(ConditionContext context, AnnotationValue requirements) {
        if (!matchesPresenceOfClasses(context, requirements)) {
            return;
        }

        if (!matchesAbsenceOfClasses(context, requirements)) {
            return;
        }

        if (!matchesEnvironment(context, requirements)) {
            return;
        }

        if (!matchesPresenceOfEntities(context, requirements)) {
            return;
        }

        if (!matchesProperty(context,  requirements)) {
            return;
        }
        if (!matchesMissingProperty(context,  requirements)) {
            return;
        }

        if (!matchesConfiguration(context, requirements)) {
            return;
        }

        if (!matchesSdk(context, requirements)) {
            return;
        }

        if (!matchesPresenceOfResources(context, requirements)) {
            return;
        }

        if (!matchesCurrentOs(context, requirements)) {
            return;
        }

        // need this check because when this method is called with a BeanDefinitionReference the context
        // is not yet initialized, so we cannot know if beans are present or not
        // check only that the classes are present for the beans requirement
        matchesPresenceOfClasses(context, requirements, MEMBER_BEANS);
    }

    /**
     * This method will run conditions that require all beans to be loaded. These conditions included "beans", "bean", "missingBeans" and custom conditions.
     */
    private void processPostStartRequirements(ConditionContext context, AnnotationValue requirements) {
        processPreStartRequirements(context, requirements);

        if (context.isFailing()) {
            return;
        }

        if (!matchesPresenceOfBeans(context, requirements)) {
            return;
        }

        if (!matchesAbsenceOfBeans(context, requirements)) {
            return;
        }

        matchesCustomConditions(context, requirements);
    }

    private boolean matchesProperty(ConditionContext context, AnnotationValue requirements) {
        if (requirements.contains(MEMBER_PROPERTY)) {
            String property = requirements.stringValue(MEMBER_PROPERTY).orElse(null);
            if (StringUtils.isNotEmpty(property)) {
                String value = requirements.stringValue().orElse(null);
                BeanContext beanContext = context.getBeanContext();
                if (beanContext instanceof PropertyResolver propertyResolver) {
                    String defaultValue = requirements.stringValue(MEMBER_DEFAULT_VALUE).orElse(null);
                    if (!propertyResolver.containsProperties(property) && StringUtils.isEmpty(defaultValue)) {
                        boolean hasNotEquals = requirements.contains(MEMBER_NOT_EQUALS);
                        if (hasNotEquals) {
                            return true;
                        } else {
                            context.fail("Required property [" + property + "] with value [" + value + "] not present");
                            return false;
                        }
                    } else if (StringUtils.isNotEmpty(value)) {
                        String resolved = resolvePropertyValue(property, propertyResolver, defaultValue);
                        boolean result = resolved != null && resolved.equals(value);
                        if (!result) {
                            context.fail("Property [" + property + "] with value [" + resolved + "] does not equal required value: " + value);
                        }
                        return result;
                    } else if (requirements.contains(MEMBER_NOT_EQUALS)) {
                        String notEquals = requirements.stringValue(MEMBER_NOT_EQUALS).orElse(null);
                        String resolved = resolvePropertyValue(property, propertyResolver, defaultValue);
                        boolean result = resolved == null || !resolved.equals(notEquals);
                        if (!result) {
                            context.fail("Property [" + property + "] with value [" + resolved + "] should not equal: " + notEquals);
                        }
                        return result;
                    } else if (requirements.contains(MEMBER_PATTERN)) {
                        String pattern = requirements.stringValue(MEMBER_PATTERN).orElse(null);
                        if (pattern == null) {
                            return true;
                        }
                        String resolved = resolvePropertyValue(property, propertyResolver, defaultValue);
                        boolean result = resolved != null && resolved.matches(pattern);
                        if (!result) {
                            context.fail("Property [" + property + "] with value [" + resolved + "] does not match required pattern: " + pattern);
                        }
                        return result;
                    }
                } else {
                    context.fail("Bean requires property but BeanContext does not support property resolution");
                    return false;
                }
            }
        }
        return true;
    }

    private String resolvePropertyValue(String property, PropertyResolver propertyResolver, String defaultValue) {
        return propertyResolver.getProperty(property, ConversionContext.STRING).orElse(defaultValue);
    }

    private boolean matchesMissingProperty(ConditionContext context, AnnotationValue requirements) {
        if (requirements.contains(MEMBER_MISSING_PROPERTY)) {
            String property = requirements.stringValue(MEMBER_MISSING_PROPERTY).orElse(null);
            if (StringUtils.isNotEmpty(property)) {
                BeanContext beanContext = context.getBeanContext();
                if (beanContext instanceof PropertyResolver propertyResolver) {
                    if (propertyResolver.containsProperties(property)) {
                        context.fail("Property [" + property + "] present");
                        return false;
                    }
                }
            }
        }
        return true;
    }

    private boolean matchesEnvironment(ConditionContext context, AnnotationValue requirements) {
        if (requirements.contains(MEMBER_ENV)) {
            String[] env = requirements.stringValues(MEMBER_ENV);
            if (ArrayUtils.isNotEmpty(env)) {
                BeanContext beanContext = context.getBeanContext();
                if (beanContext instanceof ApplicationContext applicationContext) {
                    Environment environment = applicationContext.getEnvironment();
                    Set activeNames = environment.getActiveNames();
                    boolean result = Arrays.stream(env).anyMatch(activeNames::contains);
                    if (!result) {
                        context.fail("None of the required environments [" + ArrayUtils.toString(env) + "] are active: " + activeNames);
                    }
                    return result;
                }
            }
        } else if (requirements.contains(MEMBER_NOT_ENV)) {
            String[] env = requirements.stringValues(MEMBER_NOT_ENV);
            if (ArrayUtils.isNotEmpty(env)) {
                BeanContext beanContext = context.getBeanContext();
                if (beanContext instanceof ApplicationContext applicationContext) {
                    Environment environment = applicationContext.getEnvironment();
                    Set activeNames = environment.getActiveNames();
                    boolean result = Arrays.stream(env).noneMatch(activeNames::contains);
                    if (!result) {
                        context.fail("Disallowed environments [" + ArrayUtils.toString(env) + "] are active: " + activeNames);
                    }
                    return result;
                }

            }
            return true;
        }
        return true;
    }

    @SuppressWarnings("unchecked")
    private boolean matchesCustomConditions(ConditionContext context, AnnotationValue requirements) {
        if (requirements.contains(MEMBER_CONDITION)) {
            final AnnotationClassValue annotationClassValue = requirements.annotationClassValue(MEMBER_CONDITION).orElse(null);
            if (annotationClassValue == null) {
                return true;
            }
            final Object instance = annotationClassValue.getInstance().orElse(null);
            if (instance instanceof Condition condition) {
                final boolean conditionResult = condition.matches(context);
                if (!conditionResult) {
                    context.fail("Custom condition [" + instance.getClass() + "] failed evaluation");
                }
                return conditionResult;
            }
            final Class conditionClass = annotationClassValue.getType().orElse(null);
            if (conditionClass == null || conditionClass == TrueCondition.class || !Condition.class.isAssignableFrom(conditionClass)) {
                return true;
            }
            // try first via instantiated metadata
            Optional condition = InstantiationUtils.tryInstantiate((Class) conditionClass);
            if (condition.isPresent()) {
                boolean conditionResult = condition.get().matches(context);
                if (!conditionResult) {
                    context.fail("Custom condition [" + conditionClass + "] failed evaluation");
                }
                return conditionResult;
            }
            // maybe a Groovy closure
            Optional> constructor = ReflectionUtils.findConstructor((Class) conditionClass, Object.class, Object.class);
            boolean conditionResult = constructor.flatMap(ctor ->
                    InstantiationUtils.tryInstantiate(ctor, null, null)
            ).flatMap(obj -> {
                Optional method = ReflectionUtils.findMethod(obj.getClass(), "call", ConditionContext.class);
                if (method.isPresent()) {
                    Object result = ReflectionUtils.invokeMethod(obj, method.get(), context);
                    if (result instanceof Boolean boolean1) {
                        return Optional.of(boolean1);
                    }
                }
                return Optional.empty();
            }).orElse(false);
            if (!conditionResult) {
                context.fail("Custom condition [" + conditionClass + "] failed evaluation");
            }
            return conditionResult;

        }
        return !context.isFailing();
    }

    private boolean matchesSdk(ConditionContext context, AnnotationValue requirements) {
        if (requirements.contains(MEMBER_SDK)) {
            Requires.Sdk sdk = requirements.enumValue(MEMBER_SDK, Requires.Sdk.class).orElse(null);
            String version = requirements.stringValue(MEMBER_VERSION).orElse(null);
            if (sdk != null && StringUtils.isNotEmpty(version)) {

                switch (sdk) {
                    case GROOVY:
                        String groovyVersion = GroovySystem.getVersion();
                        boolean versionMatch = SemanticVersion.isAtLeast(groovyVersion, version);
                        if (!versionMatch) {
                            context.fail("Groovy version [" + groovyVersion + "] must be at least " + version);
                        }
                        return versionMatch;
                    case KOTLIN:
                        String kotlinVersion = KotlinVersion.CURRENT.toString();
                        boolean isSupported = SemanticVersion.isAtLeast(kotlinVersion, version);
                        if (!isSupported) {
                            context.fail("Kotlin version [" + kotlinVersion + "] must be at least " + version);
                        }
                        return isSupported;
                    case JAVA:
                        String javaVersion = CachedEnvironment.getProperty("java.version");
                        try {
                            boolean result = SemanticVersion.isAtLeast(javaVersion, version);
                            if (!result) {
                                context.fail("Java version [" + javaVersion + "] must be at least " + version);
                            }
                            return result;
                        } catch (Exception e) {
                            if (javaVersion != null) {

                                // non-semantic versioning in play
                                int majorVersion = resolveJavaMajorVersion(javaVersion);
                                @SuppressWarnings("java:S2259") // false positive
                                int requiredVersion = resolveJavaMajorVersion(version);

                                if (majorVersion >= requiredVersion) {
                                    return true;
                                } else {
                                    context.fail("Java major version [" + majorVersion + "] must be at least " + requiredVersion);
                                }
                            } else {
                                int requiredVersion = resolveJavaMajorVersion(version);
                                context.fail("Java major version must be at least " + requiredVersion);
                            }
                        }

                        return context.isFailing();
                    default:
                        boolean versionCheck = VersionUtils.isAtLeastMicronautVersion(version);
                        if (!versionCheck) {
                            context.fail("Micronaut version [" + VersionUtils.MICRONAUT_VERSION + "] must be at least " + version);
                        }
                        return versionCheck;
                }
            }
        }
        return true;
    }

    private int resolveJavaMajorVersion(String javaVersion) {
        int majorVersion = 0;
        if (javaVersion.indexOf('.') > -1) {
            String[] tokens = javaVersion.split("\\.");
            String first = tokens[0];
            if (first.length() == 1) {
                majorVersion = first.charAt(0);
                if (Character.isDigit(majorVersion)) {
                    if (majorVersion == '1' && tokens.length > 1) {
                        majorVersion = tokens[1].charAt(0);
                    }
                }
            } else {
                try {
                    majorVersion = Integer.parseInt(first);
                } catch (NumberFormatException e) {
                    // ignore
                }
            }
        } else {
            if (javaVersion.length() == 1) {
                char ch = javaVersion.charAt(0);
                if (Character.isDigit(ch)) {
                    majorVersion = ch;
                }
            } else {
                try {
                    majorVersion = Integer.parseInt(javaVersion);
                } catch (NumberFormatException e) {
                    // ignore
                }
            }
        }
        return majorVersion;
    }

    private boolean matchesPresenceOfClasses(ConditionContext context, AnnotationValue convertibleValues) {
        return matchesPresenceOfClasses(context, convertibleValues, MEMBER_CLASSES);
    }

    private boolean matchesAbsenceOfClasses(ConditionContext context, AnnotationValue requirements) {
        if (requirements.contains(MEMBER_MISSING_CLASSES)) {
            AnnotationClassValue[] classValues = requirements.annotationClassValues(MEMBER_MISSING_CLASSES);
            if (ArrayUtils.isNotEmpty(classValues)) {
                for (AnnotationClassValue classValue : classValues) {
                    if (classValue.getType().isPresent()) {
                        context.fail("Class [" + classValue.getName() + "] is not absent");
                        return false;
                    }
                }
            } else {
                return matchAbsenceOfClassNames(context, requirements);
            }
        }
        return true;
    }

    private boolean matchAbsenceOfClassNames(ConditionContext context, AnnotationValue requirements) {
        if (requirements.contains(MEMBER_MISSING_CLASSES)) {
            final String[] classNameArray = requirements.stringValues(MEMBER_MISSING_CLASSES);
            final ClassLoader classLoader = context.getBeanContext().getClassLoader();
            for (String name : classNameArray) {
                if (ClassUtils.isPresent(name, classLoader)) {
                    context.fail("Class [" + name + "] is not absent");
                    return false;
                }
            }
        }
        return true;
    }

    private boolean matchesPresenceOfClasses(ConditionContext context, AnnotationValue requirements, String attr) {
        if (requirements.contains(attr)) {
            AnnotationClassValue[] classValues = requirements.annotationClassValues(attr);
            for (AnnotationClassValue classValue : classValues) {
                if (classValue.getType().isEmpty()) {
                    context.fail("Class [" + classValue.getName() + "] is not present");
                    return false;
                }
            }
        }
        return true;
    }

    private boolean matchesPresenceOfEntities(ConditionContext context, AnnotationValue annotationValue) {
        if (annotationValue.contains(MEMBER_ENTITIES)) {
            AnnotationClassValue[] classNames = annotationValue.annotationClassValues(MEMBER_ENTITIES);
            if (ArrayUtils.isNotEmpty(classNames)) {
                BeanContext beanContext = context.getBeanContext();
                if (beanContext instanceof ApplicationContext applicationContext) {
                    for (AnnotationClassValue classValue : classNames) {
                        final Optional> entityType = classValue.getType();
                        if (entityType.isEmpty()) {
                            context.fail("Annotation type [" + classValue.getName() + "] not present on classpath");
                            return false;
                        } else {
                            Environment environment = applicationContext.getEnvironment();
                            Class annotationType = entityType.get();
                            if (environment.scan(annotationType).findFirst().isEmpty()) {
                                context.fail("No entities found in packages [" + String.join(", ", environment.getPackages()) + "] for annotation: " + annotationType);
                                return false;
                            }
                        }
                    }
                }
            }
        }
        return true;
    }

    private boolean matchesPresenceOfBeans(ConditionContext context, AnnotationValue requirements) {
        if (requirements.contains(MEMBER_BEANS) || requirements.contains(MEMBER_BEAN)) {
            Class[] beans = requirements.classValues(MEMBER_BEANS);
            if (requirements.contains(MEMBER_BEAN)) {
                Class memberBean = requirements.classValue(MEMBER_BEAN).orElse(null);
                if (memberBean != null) {
                    beans = ArrayUtils.concat(beans, memberBean);
                }
            }
            if (ArrayUtils.isNotEmpty(beans)) {
                BeanContext beanContext = context.getBeanContext();
                for (Class type : beans) {
                    if (!beanContext.containsBean(type)) {
                        context.fail("No bean of type [" + type.getName() + "] present within context");
                        return false;
                    }
                }
            }
        }
        return true;
    }

    private boolean matchesAbsenceOfBeans(ConditionContext context, AnnotationValue requirements) {
        if (requirements.contains(MEMBER_MISSING_BEANS)) {
            Class[] missingBeans = requirements.classValues(MEMBER_MISSING_BEANS);
            AnnotationMetadataProvider component = context.getComponent();
            if (ArrayUtils.isNotEmpty(missingBeans) && component instanceof BeanDefinition bd) {
                DefaultBeanContext beanContext = (DefaultBeanContext) context.getBeanContext();

                for (Class type : missingBeans) {
                    // remove self by passing definition as filter
                    final Collection> beanDefinitions = beanContext.findBeanCandidates(
                            context.getBeanResolutionContext(),
                            Argument.of(type),
                            bd
                    );
                    for (BeanDefinition beanDefinition : beanDefinitions) {
                        if (!beanDefinition.isAbstract()) {
                            context.fail("Existing bean [" + beanDefinition.getName() + "] of type [" + type.getName() + "] registered in context");
                            return false;
                        }
                    }
                }
            }
        }
        return true;
    }

    private boolean matchesPresenceOfResources(ConditionContext context, AnnotationValue requirements) {
        if (requirements.contains(MEMBER_RESOURCES)) {
            final String[] resourcePaths = requirements.stringValues(MEMBER_RESOURCES);
            if (ArrayUtils.isNotEmpty(resourcePaths)) {
                final BeanContext beanContext = context.getBeanContext();
                ResourceResolver resolver;
                final List resourceLoaders;
                if (beanContext instanceof ApplicationContext applicationContext) {
                    ResourceLoader resourceLoader = applicationContext.getEnvironment();
                    resourceLoaders = Arrays.asList(resourceLoader, FileSystemResourceLoader.defaultLoader());
                } else {
                    resourceLoaders = Arrays.asList(
                            ClassPathResourceLoader.defaultLoader(beanContext.getClassLoader()),
                            FileSystemResourceLoader.defaultLoader()
                    );
                }
                resolver = new ResourceResolver(resourceLoaders);
                for (String resourcePath : resourcePaths) {
                    if (resolver.getResource(resourcePath).isEmpty()) {
                        context.fail("Resource [" + resourcePath + "] does not exist");
                        return false;
                    }
                }
            }
        }
        return true;
    }

    private boolean matchesCurrentOs(ConditionContext context, AnnotationValue requirements) {
        if (requirements.contains(MEMBER_OS)) {
            final Set os = requirements.enumValuesSet(MEMBER_OS, Requires.Family.class);
            Requires.Family currentOs = OperatingSystem.getCurrent().getFamily();
            if (!os.contains(currentOs)) {
                context.fail("The current operating system [" + currentOs.name() + "] is not one of the required systems [" + os + "]");
                return false;
            }
        } else if (requirements.contains(MEMBER_NOT_OS)) {
            Requires.Family currentOs = OperatingSystem.getCurrent().getFamily();
            final Set notOs = requirements.enumValuesSet(MEMBER_NOT_OS, Requires.Family.class);
            if (notOs.contains(currentOs)) {
                context.fail("The current operating system [" + currentOs.name() + "] is one of the disallowed systems [" + notOs + "]");
                return false;
            }
        }
        return true;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy