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

net.n2oapp.framework.api.StringUtils Maven / Gradle / Ivy

There is a newer version: 7.28.1
Show newest version
package net.n2oapp.framework.api;

import net.n2oapp.framework.api.context.Context;
import net.n2oapp.framework.api.exception.NotFoundContextPlaceholderException;
import net.n2oapp.framework.api.metadata.validation.exception.N2oMetadataValidationException;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.lang.Nullable;
import org.springframework.validation.ValidationUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.util.Objects.nonNull;
import static net.n2oapp.framework.api.PlaceHoldersResolver.replaceNullByEmpty;
import static net.n2oapp.framework.api.PlaceHoldersResolver.replaceOptional;


/**
 * Утилиты для работы с особыми строками в N2O
 */
public abstract class StringUtils {
    private static PlaceHoldersResolver propertyPlaceHoldersResolver = new PlaceHoldersResolver("${", "}");
    private static PlaceHoldersResolver contextPlaceHoldersResolver = new PlaceHoldersResolver("#{", "}");
    private static PlaceHoldersResolver jsPlaceHoldersResolver = new PlaceHoldersResolver("`", "`");
    private static PlaceHoldersResolver linkPlaceHoldersResolver = new PlaceHoldersResolver("{", "}");
    private static PlaceHoldersResolver jsonPlaceHoldersResolver = new PlaceHoldersResolver("{{", "}}");
    private static final String PATTERN = "^([a-zA-Z$_][a-zA-Z0-9$_]*\\(\\))$";

    /**
     * Проверка, что строка - настройка
     * Примеры:
     * {@code
     * isProperty("${prop}");      //true
     * isProperty("prop");         //false
     * isProperty("{prop}");       //false
     * }
     *
     * @param s - строка
     * @return Да (true), нет (false)
     */
    public static boolean isProperty(String s) {
        return propertyPlaceHoldersResolver.isPlaceHolder(s);
    }

    /**
     * Проверка, что текст содержит настройки
     * Примеры:
     * {@code
     * hasProperty("${prop}");             //true
     * hasProperty("ab ${prop} cd");       //true
     * hasProperty("abcd");                //false
     * hasProperty("ab {prop} cd");        //false
     * }
     *
     * @param text Текст
     * @return Содержит (true) или нет (false)
     */
    public static boolean hasProperty(String text) {
        return propertyPlaceHoldersResolver.hasPlaceHolders(text);
    }

    /**
     * Проверка, что строка - это контекст
     * Примеры:
     * isContext("#{username}");       //true
     * isContext("username");          //false
     * isContext("{username}");        //false
     *
     * @param s - строка
     * @return true - контекст, false - не контекст
     */
    public static boolean isContext(String s) {
        return contextPlaceHoldersResolver.isPlaceHolder(s);
    }

    /**
     * Проверка, что строка содержит контекст
     * Примеры:
     * hasContext("#{username}");             //true
     * hasContext("ab #{username} cd");       //true
     * hasContext("ab username cd");          //false
     * hasContext("ab {username} cd");        //false
     *
     * @param text Текст
     * @return Содержит (true) или нет (false)
     */
    public static boolean hasContext(String text) {
        return contextPlaceHoldersResolver.hasPlaceHolders(text);
    }

    /**
     * Проверка, что значение - ссылка.
     * Примеры:
     * {@code
     * isLink("{abc}");        //true
     * isLink("abc");          //false
     * isLink("{"a" : "b"}");  //false
     * }
     *
     * @param value Значение
     * @return Является ссылкой (true)
     */
    public static boolean isLink(Object value) {
        return linkPlaceHoldersResolver.isPlaceHolder(value) && !jsonPlaceHoldersResolver.isPlaceHolder(value);
    }

    /**
     * Получение текста внутри ссылки
     *
     * @param text Ссылка
     * @return Текст внутри ссылки или null, если входящий текст не является ссылкой
     */
    public static String unwrapLink(String text) {
        return isLink(text) ? text.substring(1, text.length() - 1) : null;
    }

    /**
     * Проверка, что строка окаймлена экранированными символами
     * Примеры:
     * {@code
     * isEscapedString("'true'");  //true
     * isEscapedString("'123'");   //true
     * isEscapedString("true");    //false
     * }
     *
     * @param text Текст
     * @return true - окаймлена, false - не окаймлена
     */
    public static boolean isEscapedString(String text) {
        return text.startsWith("'") && text.endsWith("'");
    }

    /**
     * Получение текста внутри экранированных символов
     *
     * @param text Текст
     * @return Текст без экранированных символов или исходный текст
     */
    public static String unwrapEscapedString(String text) {
        return isEscapedString(text) ? text.substring(1, text.length() - 1) : text;
    }

    /**
     * Проверка, что значение - json(то есть обрамлено двойными {{ }} )
     * Примеры:
     * {@code
     * isJson("{{"a" : "b"}}");        //true
     * isJson("{"a" : "b"}");          //false
     * }
     *
     * @param value Значение
     * @return Является json (true)
     */
    public static boolean isJson(Object value) {
        return jsonPlaceHoldersResolver.isPlaceHolder(value);
    }

    /**
     * Проверка, что строка содержит ссылку.
     * Примеры:
     * {@code
     * hasLink("{username}");               //true
     * hasLink("ab {username} cd");         //true
     * hasLink("ab username cd");           //false
     * hasLink("ab ${username} cd");        //false
     * }
     *
     * @param text Текст
     * @return Содержит (true) или нет (false)
     */
    public static boolean hasLink(String text) {
        return text != null && text.matches("[\\s\\S]*(? properties) {
        return propertyPlaceHoldersResolver.resolve(text, properties);
    }

    /**
     * Заменить в тексте плейсхолдеры с контекстом
     *
     * @param text    Текст с плейсхолдерами #{...}
     * @param context Контекст
     * @return Текст без плейсхолдеров
     */
    public static String resolveContext(String text, Context context) {
        try {
            return contextPlaceHoldersResolver.resolve(text, PlaceHoldersResolver.replaceNullByEmpty(replaceOptional(context::get)));
        } catch (NotFoundPlaceholderException e) {
            throw new NotFoundContextPlaceholderException(e.getPlaceholder());
        }
    }

    /**
     * Заменить в тексте плейсхолдеры с ссылками
     *
     * @param text Текст с плейсхолдерами {...}
     * @param data Значения ссылок
     * @return Текст без плейсхолдеров
     */
    public static String resolveLinks(String text, Object data) {
        return linkPlaceHoldersResolver.resolve(text, replaceNullByEmpty(data));
    }

    /**
     * Заменить в тексте плейсхолдеры с ссылками
     *
     * @param text Текст с плейсхолдерами {...}
     * @param data Функция для получения значений ссылок
     * @return Текст без плейсхолдеров
     */
    public static String resolveLinks(String text, Function data) {
        return linkPlaceHoldersResolver.resolve(text, PlaceHoldersResolver.replaceNullByEmpty(data));
    }

    /**
     * Собрать в тексте плейсхолдеры с ссылками
     *
     * @param text Текст с плейсхолдерами {...}
     * @return Список параметров из плейсхолдеров
     */
    public static Set collectLinks(String text) {
        return linkPlaceHoldersResolver.extractPlaceHolders(text);
    }

    /**
     * Сравнивает строку на соответствие маске
     *
     * @param mask - маска (* - любые символы)
     * @param val  - сравниваемое значение
     * @return - результат сравнения
     */
    public static boolean maskMatch(String mask, String val) {
        return mask == null || val == null ?
                mask == null && val == null :
                val.matches(maskToRegex(mask));
    }

    /**
     * Конвертирует маску в RegEx
     *
     * @param mask - маска (* - любые символы)
     * @return - регулярное выражение
     */
    public static String maskToRegex(String mask) {
        if (mask == null) {
            return null;
        }
        if (!mask.contains("*")) {
            return "\\Q" + mask + "\\E";
        }

        StringBuilder sb = new StringBuilder();
        if (mask.startsWith("*")) {
            sb.append("(.*)");
        }
        String[] pieces = mask.split("\\*");
        for (int i = 0; i < pieces.length; i++) {
            if (!pieces[i].isEmpty()) {
                sb.append("\\Q").append(pieces[i]).append("\\E");
                if (i + 1 < pieces.length || mask.endsWith("*")) {
                    sb.append("(.*)");
                }
            }
        }
        return sb.toString();
    }

    /**
     * Проверка, что текст содержит шаблон поиска
     *
     * @param str Строка
     * @return Содержит (true) или нет (false)
     */
    public static boolean hasWildcard(String str) {
        if (str == null)
            return false;
        return str.contains("*");
    }

    public static boolean isEmpty(@Nullable Object str) {
        return (str == null || "".equals(str));
    }

    public static boolean isSpel(String str) {
        if (str == null)
            return false;
        return str.startsWith("[") && str.endsWith("]");
    }

    public static String unwrapSpel(String str) {
        if (!isSpel(str))
            return str;
        int num = str.contains("'") ? 2 : 1;
        return str.substring(num, str.length() - num);
    }


    /**
     * Преобразование атрибута размера к корректному формату.
     * Если оно представлено числом, то значение + "px".
     * Иначе строка в исходном виде.
     * Примеры:
     * {@code
     * prepareSizeAttribute("100");    //"100px"
     * prepareSizeAttribute("100.5");  //"100.5px"
     * prepareSizeAttribute("150em");  //"150em"
     * prepareSizeAttribute("200px");  //"200px"
     * }
     *
     * @param value Значение
     * @return Значение атрибута размера в корректном формате
     */

    public static String prepareSizeAttribute(String value) {
        return NumberUtils.isCreatable(value) ? value.concat("px") : value;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy