<commit_before>/*
 * oxTrust is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
 *
 * Copyright (c) 2019, Gluu
 */
package org.gluu.oxtrust.service.antlr.scimFilter;

import org.gluu.oxtrust.model.scim2.AttributeDefinition.Type;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.gluu.oxtrust.model.scim2.util.DateUtil;
import org.gluu.oxtrust.service.antlr.scimFilter.enums.CompValueType;
import org.gluu.oxtrust.service.antlr.scimFilter.enums.ScimOperator;
import org.gluu.oxtrust.service.antlr.scimFilter.util.FilterUtil;
import org.gluu.search.filter.Filter;
import org.gluu.util.Pair;

import java.util.Optional;

public class SubFilterGenerator {

    Logger log = LogManager.getLogger(getClass());

    private boolean ldapBackend;
    private String error;

    public SubFilterGenerator(boolean ldapBackend) {
        this.ldapBackend = ldapBackend;
    }

    /**
     * Computes a filter based on an atomic (non-divisible) SCIM expression described by the set of parameters passed.
     * If the filter cannot be built, null is returned.
     * @param subAttribute The name of the json property upon which the search is acting. If the search is targetted
     *                     directly upon an attribute, this is null
     * @param attribute The attribute of interest. If the attribute contains json contents, the search can be focused on
     *                  a sub-attribute inside it
     * @param compValue The comparison value (it's found after the operator, e.g "hi" in displayName co "hi")
     * @param attrType The attribute definition type of the attribute
     * @param type See compvalue in ScimFilter.g4 grammar file
     * @param operator The operator
     * @param multiValued Whether the attribute referenced in parameter is multivalued or not
     * @return The filter built after processing this atomic expression (accompanied with an error string if any)
     */
    public Pair<Filter, String> build(String subAttribute, String attribute, String compValue, Type attrType,
                                      CompValueType type, ScimOperator operator, boolean multiValued) {

        Filter filth = null;
        error = null;

        if (type.equals(CompValueType.NULL)) {
            if (subAttribute == null) {
                //attribute=*
                //attribute IS NOT MISSING
                filth = Filter.createPresenceFilter(attribute);
                filth = negateIf(filth, operator.equals(ScimOperator.EQUAL));
            } else {
                //attribute=*"subattribute":null*
                //attribute LIKE "%\"subattribute\":null%"
                String sub = String.format("\"%s\":null", subAttribute);
                filth = Filter.createSubstringFilter(attribute, null, new String[]{ sub }, null);
                filth = negateIf(filth, operator.equals(ScimOperator.NOT_EQUAL));
            }
        } else if (Type.STRING.equals(attrType) || Type.REFERENCE.equals(attrType)) {
            compValue = compValue.substring(1, compValue.length() - 1);     //Drop double quotes
            filth = getSubFilterString(subAttribute, attribute, StringEscapeUtils.unescapeJson(compValue), operator, multiValued);

        } else if (Type.INTEGER.equals(attrType) || Type.DECIMAL.equals(attrType)) {
            filth = getSubFilterNumeric(subAttribute, attribute, compValue, operator, attrType, multiValued);

        } else if (Type.BOOLEAN.equals(attrType)) {
            filth = getSubFilterBoolean(subAttribute, attribute, compValue, operator, multiValued);

        } else if (Type.DATETIME.equals(attrType)) {
            compValue = compValue.substring(1, compValue.length() - 1);
            //Dates dol not have characters to escape...
            filth = getSubFilterDateTime(subAttribute, attribute, compValue, operator, multiValued);

        }
        log.trace("getSubFilter. {}", Optional.ofNullable(filth).map(Filter::toString).orElse(null));
        return new Pair<>(filth, error);

    }

    private Filter getSubFilterString(String subAttribute, String attribute, String value, ScimOperator operator, boolean multivalued) {

        Filter subfilter = null;
        log.trace("getSubFilterString");

        switch (operator) {
            case EQUAL:
            case NOT_EQUAL:
                if (subAttribute == null) {
                    //attribute=value
                    //attribute="value"
                    subfilter = Filter.createEqualityFilter(attribute, value).multiValued(multivalued);
                } else {
                    //attribute=*"subattribute":"value"*
                    //attribute LIKE "%\"subAttribute\":\"value\"%"
                    String sub = String.format("\"%s\":\"%s\"", subAttribute, value);
                    subfilter = Filter.createSubstringFilter(attribute, null, new String[]{ sub }, null);
                }
                subfilter = negateIf(subfilter, operator.equals(ScimOperator.NOT_EQUAL));
                break;
            case CONTAINS:
                if (subAttribute == null) {
                    //attribute=*value*
                    //attribute LIKE "%value%"
                    subfilter = Filter.createSubstringFilter(attribute, null, new String[]{ value }, null);
                } else {<commit_msg>use case insensitiveness for eq filter, #1823<commit_after>/*
 * oxTrust is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
 *
 * Copyright (c) 2019, Gluu
 */
package org.gluu.oxtrust.service.antlr.scimFilter;

import org.gluu.oxtrust.model.scim2.AttributeDefinition.Type;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.gluu.oxtrust.model.scim2.util.DateUtil;
import org.gluu.oxtrust.service.antlr.scimFilter.enums.CompValueType;
import org.gluu.oxtrust.service.antlr.scimFilter.enums.ScimOperator;
import org.gluu.oxtrust.service.antlr.scimFilter.util.FilterUtil;
import org.gluu.search.filter.Filter;
import org.gluu.util.Pair;

import java.util.Optional;

public class SubFilterGenerator {

    Logger log = LogManager.getLogger(getClass());

    private boolean ldapBackend;
    private String error;

    public SubFilterGenerator(boolean ldapBackend) {
        this.ldapBackend = ldapBackend;
    }

    /**
     * Computes a filter based on an atomic (non-divisible) SCIM expression described by the set of parameters passed.
     * If the filter cannot be built, null is returned.
     * @param subAttribute The name of the json property upon which the search is acting. If the search is targetted
     *                     directly upon an attribute, this is null
     * @param attribute The attribute of interest. If the attribute contains json contents, the search can be focused on
     *                  a sub-attribute inside it
     * @param compValue The comparison value (it's found after the operator, e.g "hi" in displayName co "hi")
     * @param attrType The attribute definition type of the attribute
     * @param type See compvalue in ScimFilter.g4 grammar file
     * @param operator The operator
     * @param multiValued Whether the attribute referenced in parameter is multivalued or not
     * @return The filter built after processing this atomic expression (accompanied with an error string if any)
     */
    public Pair<Filter, String> build(String subAttribute, String attribute, String compValue, Type attrType,
                                      CompValueType type, ScimOperator operator, boolean multiValued) {

        Filter filth = null;
        error = null;

        if (type.equals(CompValueType.NULL)) {
            if (subAttribute == null) {
                //attribute=*
                //attribute IS NOT MISSING
                filth = Filter.createPresenceFilter(attribute);
                filth = negateIf(filth, operator.equals(ScimOperator.EQUAL));
            } else {
                //attribute=*"subattribute":null*
                //attribute LIKE "%\"subattribute\":null%"
                String sub = String.format("\"%s\":null", subAttribute);
                filth = Filter.createSubstringFilter(attribute, null, new String[]{ sub }, null);
                filth = negateIf(filth, operator.equals(ScimOperator.NOT_EQUAL));
            }
        } else if (Type.STRING.equals(attrType) || Type.REFERENCE.equals(attrType)) {
            compValue = compValue.substring(1, compValue.length() - 1);     //Drop double quotes
            filth = getSubFilterString(subAttribute, attribute, StringEscapeUtils.unescapeJson(compValue), operator, multiValued);

        } else if (Type.INTEGER.equals(attrType) || Type.DECIMAL.equals(attrType)) {
            filth = getSubFilterNumeric(subAttribute, attribute, compValue, operator, attrType, multiValued);

        } else if (Type.BOOLEAN.equals(attrType)) {
            filth = getSubFilterBoolean(subAttribute, attribute, compValue, operator, multiValued);

        } else if (Type.DATETIME.equals(attrType)) {
            compValue = compValue.substring(1, compValue.length() - 1);
            //Dates dol not have characters to escape...
            filth = getSubFilterDateTime(subAttribute, attribute, compValue, operator, multiValued);

        }
        log.trace("getSubFilter. {}", Optional.ofNullable(filth).map(Filter::toString).orElse(null));
        return new Pair<>(filth, error);

    }

    private Filter getSubFilterString(String subAttribute, String attribute, String value, ScimOperator operator, boolean multivalued) {

        Filter subfilter = null;
        log.trace("getSubFilterString");

        switch (operator) {
            case EQUAL:
            case NOT_EQUAL:
                if (subAttribute == null) {
                    //attribute=value
                    //attribute="value"
                    subfilter = Filter.createEqualityFilter(Filter.createLowercaseFilter(attribute), ldapBackend ? value : value.toLowerCase())
                            .multiValued(multivalued);
                } else {
                    //attribute=*"subattribute":"value"*
                    //attribute LIKE "%\"subAttribute\":\"value\"%"
                    String sub = String.format("\"%s\":\"%s\"", subAttribute, value);
                    subfilter = Filter.createSubstringFilter(attribute, null, new String[]{ sub }, null);
                }
                subfilter = negateIf(subfilter, operator.equals(ScimOperator.NOT_EQUAL));
                break;
            case CONTAINS:
                if (subAttribute == null) {
                    //attribute=*value*
                    //attribute LIKE "%value%"
                    subfilter = Filter.createSubstringFilter(attribute, null, new String[]{ value }, null);
                } else {
{'fraction_non_alphanumeric': 0.10011875399652873, 'fraction_numerical': 0.0036539691239609027, 'mean_word_length': 2.4910714285714284, 'pattern_counts': {'":': 12, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2019993', 'n_tokens_mistral': 2954, 'n_tokens_neox': 2839, 'n_words': 781}