class VersionDistancePolicyEvaluator extends AbstractPolicyEvaluator {

    private static final Logger LOGGER = Logger.getLogger(VersionDistancePolicyEvaluator.class);

    /**
     * {@inheritDoc}
     */
    @Override
    public PolicyCondition.Subject supportedSubject() {
        return PolicyCondition.Subject.VERSION_DISTANCE;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<PolicyConditionViolation> evaluate(final Policy policy, final Component component) {<FILL_FUNCTION_BODY>}

    /**
     * Evaluate VersionDistance conditions for a given versionDistance. A condition
     *
     * @param condition operator and value containing combined {@link VersionDistance} values
     * @param versionDistance the {@link VersionDistance} to evalue
     * @return true if the condition is true for the components versionDistance, false otherwise
     */
    private boolean evaluate(final PolicyCondition condition, final VersionDistance versionDistance) {
        final var operator = condition.getOperator();
        final var value = condition.getValue();

        if (!StringUtils.isEmpty(value)) {
            final var json = new JSONObject(value);
            final var epoch = json.optString("epoch", "0");
            final var major = json.optString("major", "?");
            final var minor = json.optString("minor", "?");
            final var patch = json.optString("patch", "?");

            final List<VersionDistance> versionDistanceList;
            try {
                versionDistanceList = VersionDistance.parse(epoch+":"+major+"."+minor+"."+patch);
            } catch (IllegalArgumentException e) {
                LOGGER.error("Invalid version distance format", e);
                return false;
            }
            if (versionDistanceList.isEmpty()) {
                versionDistanceList.add(new VersionDistance(0,0,0));
            }
            return versionDistanceList.stream().reduce(
                false,
                (latest, current) -> latest || matches(operator, current, versionDistance),
                Boolean::logicalOr
            );
        }
        return false;



    }

    private boolean matches(final Operator operator, final VersionDistance policyDistance, final VersionDistance versionDistance) {
        return switch (operator) {
            case NUMERIC_GREATER_THAN -> versionDistance.compareTo(policyDistance) > 0;
            case NUMERIC_GREATER_THAN_OR_EQUAL -> versionDistance.compareTo(policyDistance) >= 0;
            case NUMERIC_EQUAL -> versionDistance.compareTo(policyDistance) == 0;
            case NUMERIC_NOT_EQUAL -> versionDistance.compareTo(policyDistance) != 0;
            case NUMERIC_LESSER_THAN_OR_EQUAL -> versionDistance.compareTo(policyDistance) <= 0;
            case NUMERIC_LESS_THAN -> versionDistance.compareTo(policyDistance) < 0;
            default -> {
                LOGGER.warn("Operator %s is not supported for component age conditions".formatted(operator));
                yield false;
            }
        };
    }

    /**
     * Test if the components project direct dependencies contain a given component
     * If so, the component is a direct dependency of the project
     *
     * @param component component to test
     * @return If the components project direct dependencies contain the component
     */
    private boolean isDirectDependency(Component component) {
        if (component.getProject().getDirectDependencies() == null) {
            return false;
        }

        return component.getProject().getDirectDependencies().contains("\"uuid\":\"" + component.getUuid().toString() + "\"");
    }

}

        final var violations = new ArrayList<PolicyConditionViolation>();

        if (component.getPurl() == null || component.getVersion() == null) {
            return violations;
        }

        final List<PolicyCondition> conditions = super.extractSupportedConditions(policy);
        if (conditions.isEmpty()) {
            return violations;
        }

        final RepositoryType repoType = RepositoryType.resolve(component.getPurl());
        if (RepositoryType.UNSUPPORTED == repoType) {
            return violations;
        }

        final RepositoryMetaComponent metaComponent;
        try (final var qm = new QueryManager()) {
            metaComponent = qm.getRepositoryMetaComponent(repoType,
                    component.getPurl().getNamespace(), component.getPurl().getName());
            qm.getPersistenceManager().detachCopy(metaComponent);
        }
        if (metaComponent == null || metaComponent.getLatestVersion() == null) {
            return violations;
        }

        final VersionDistance versionDistance;
        try {
            versionDistance = VersionDistance.getVersionDistance(component.getVersion(), metaComponent.getLatestVersion());
        } catch (RuntimeException e) {
            LOGGER.warn("""
                    Failed to compute version distance for component %s (UUID: %s), \
                    between component version %s and latest version %s; Skipping\
                    """.formatted(component, component.getUuid(), component.getVersion(), metaComponent.getLatestVersion()), e);
            return violations;
        }

        for (final PolicyCondition condition : conditions) {
            if (isDirectDependency(component) && evaluate(condition, versionDistance)) {
                violations.add(new PolicyConditionViolation(condition, component));
            }
        }

        return violations;
    
<methods>public non-sealed void <init>() ,public void setQueryManager(org.dependencytrack.persistence.QueryManager) <variables>protected org.dependencytrack.persistence.QueryManager qm