Алгоритм строк как в Permissions

tox1cozZ

aka Agravaine
8,455
598
2,892
Понадобилось реализовать алгоритм со строками как в плагинах на пермишаны.
То есть возможность добавлять и исключать строки, ну и конечно же чтобы работала звездочка(string.* например).
Их тонна разных, но там столько абстракций и левого кода, что нужно куска так и не смог найти...
Накидал такое чудо, вроде работает, но что-то мне не очень нравится код:
Java:
private final Set<String> strings = Sets.newTreeSet();
    private final Set<String> blockedStrings = Sets.newTreeSet();

    public boolean has(String input){
        boolean has = false;
        for(String str : strings){
            if(str.endsWith("*")){
                str = str.substring(0, str.length() - 1);
                if(input.startsWith(str)){
                    has = true;
                    break;
                }
            }else{
                if(input.equals(str)){
                    has = true;
                    break;
                }
            }
        }

        if(has){
            for(String str : blockedStrings){
                if(str.endsWith("*")){
                    str = str.substring(0, str.length() - 1);
                    if(input.startsWith(str) && !strings.contains(input)){
                        return false;
                    }
                }else{
                    if(input.equals(str)){
                        return false;
                    }
                }
            }
        }

        return has;
    }
 
7,099
324
1,510
Сделай дата-класс Permission, который эквивалентен строкам прав(существуют функции String=>Permission и Permission=>String).
Например, в виде цепочки строковых сегментов прав
Scala:
trait Permission{
    def isGreaterThan(p:Permission)
}
case object AnyAccept extends Permission{
    def isGreaterThan(_:Permission) = true
}
case class Segment(root:String,next:Permission) extends Permission{
    def isGreaterThan(p:Permission) =
        p match{
            case AnyAccept=>false
            case Segment(root1,next1)=> root==root1 && next.isGreaterThan(next1)
        }
}
Тогда алгоритм будет совсем простой
Scala:
private val strings = new HashSet[Permission]
private val blockedStrings = new HashSet[Permission]

def has(input:Permission):Boolean =
    strings.exists([I].isGreaterThan(input)) && !blockedStrings.exists([/I].isGreaterThan(input))
 
Последнее редактирование:
7,099
324
1,510
Java:
interface Permission{
    boolean isGreaterThan(Permission p);
}

public static final AnyAccept = new Permission(){
    boolean isGreaterThan(Permission __){return true;}
}

@Value //Lombok
class Segment extends Permission{
    public final String root;
    public final Permission next;

    boolean isGreaterThan(Permission p){
        if(p==AnyAccept)
            return false;
        else
            return root==((Segment)p).root && next.isGreaterThan(((Segment)p).next);

    }
}

Java:
private final Set<Permission> strings = Sets.newTreeSet();
private final Set<Permission> blockedStrings = Sets.newTreeSet();

public boolean has(Permission input){
    return strings.exists(i->i.isGreaterThan(input)) && !blockedStrings.exists(i->i.isGreaterThan(input));
}

В джавке у бедных коллекций нету метода exists(который почти как contains, только предикат может быть произвольным, а не только equals)
 
Последнее редактирование:
7,099
324
1,510
Предполагается, что в коде везде будешь работать с абстракцией Permission. Если право вводится откуда-то в виде цельной строки, то она переводится в Permission
Че-то типо того
stringPerm.split('.').foldRight(AnyAccept)((perm,stringSegm)=> Segment(stringSegm,perm))
 
7,099
324
1,510
Кстати, т.к. Permission имеет префиксную структуру, то можно хранить права в redix-tree, тогда можно будет быстро без полного пребора множества определять, имеется ли правило
 
Сверху