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

dev.cel.runtime.CelAttribute Maven / Gradle / Ivy

// Copyright 2022 Google LLC
//
// 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 dev.cel.runtime;

import com.google.auto.value.AutoOneOf;
import com.google.auto.value.AutoValue;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.UnsignedLong;
import com.google.errorprone.annotations.Immutable;
import com.google.re2j.Pattern;

/**
 * CelAttribute represents the select path from the root (.) to a single leaf value that may be
 * derived from the activation (e.g. .com.google.Attribute['index'])
 *
 * 

This includes fully qualified identifiers and the selection path to a member field or element. * *

CelAttributes are represented as a list of qualifiers (select/index operations) from the root, * e.g. identifier[2].field is represented as string:identifier, int:2, string:field. */ @Immutable @AutoValue public abstract class CelAttribute { /** * Empty attribute. Represents a value that doesn't have a corresponding attribute (e.g. the * result of a function). */ public static final CelAttribute EMPTY = new AutoValue_CelAttribute(ImmutableList.of()); /** Representation of a single select qualifier or index. */ @Immutable @AutoOneOf(Qualifier.Kind.class) public abstract static class Qualifier { private static final Pattern IDENT_PATTERN = Pattern.compile("[A-Za-z_][A-Za-z_0-9]*"); /** Legal attribute qualifier kinds. */ public enum Kind { AS_STRING, AS_INT, AS_UINT, AS_BOOL, WILD_CARD }; public static Qualifier ofString(String value) { return AutoOneOf_CelAttribute_Qualifier.asString(value); } public static Qualifier ofInt(long value) { return AutoOneOf_CelAttribute_Qualifier.asInt(value); } public static Qualifier ofUint(UnsignedLong value) { return AutoOneOf_CelAttribute_Qualifier.asUint(value); } /** Overload for integer literals. Value must be non-negative. */ public static Qualifier ofUint(long value) { Preconditions.checkArgument(value >= 0L, "uint qualifier must be non-negative."); return ofUint(UnsignedLong.valueOf(value)); } public static Qualifier ofBool(boolean value) { return AutoOneOf_CelAttribute_Qualifier.asBool(value); } public static Qualifier ofWildCard() { return AutoOneOf_CelAttribute_Qualifier.wildCard(); } public abstract Kind kind(); public abstract String asString(); public abstract Long asInt(); public abstract UnsignedLong asUint(); public abstract Boolean asBool(); public abstract void wildCard(); /** * Creates a Qualifier from a generic object. * * @throws IllegalArgumentException if the value can't be interpreted as a field selection or an * index. */ public static Qualifier fromGeneric(Object value) { if (value instanceof UnsignedLong) { return ofUint((UnsignedLong) value); } else if (value instanceof Long) { return ofInt((Long) value); } else if (value instanceof Boolean) { return ofBool((boolean) value); } else if (value instanceof String) { return ofString((String) value); } throw new IllegalArgumentException("Unsupported attribute qualifier kind"); } public String toIndexFormat() { String key = ""; switch (kind()) { case AS_STRING: key = "'" + asString() + "'"; break; case AS_INT: key = asInt().toString(); break; case AS_UINT: key = asUint().toString() + "u"; break; case AS_BOOL: key = asBool() ? "true" : "false"; break; default: throw new IllegalStateException( String.format("Unsupported CEL attribute qualifier for index: %s", kind())); } return String.format("[%s]", key); } /** * Simple test that an identifier segment is a legal CEL identifier. This does not check for * reserved names. */ public static boolean isLegalIdentifier(String identifier) { return IDENT_PATTERN.matches(identifier); } public static boolean isLegalIdentifier(Qualifier identifier) { return identifier.kind() == Kind.AS_STRING && isLegalIdentifier(identifier.asString()); } } /** Creates a CelAttribute. */ public static CelAttribute create(ImmutableList qualifiers) { Preconditions.checkArgument(!qualifiers.isEmpty(), "qualifiers must be non-empty"); Preconditions.checkArgument( Qualifier.isLegalIdentifier(qualifiers.get(0)), "'%s' is not a legal CEL identifier", qualifiers.get(0)); qualifiers.forEach( q -> Preconditions.checkArgument( q.kind() != Qualifier.Kind.WILD_CARD, "Wildcards are not permitted in CelAttributes.")); return new AutoValue_CelAttribute(qualifiers); } /** Creates a CelAttribute from a single root identifier. */ public static CelAttribute create(String rootIdentifier) { Preconditions.checkArgument( Qualifier.isLegalIdentifier(rootIdentifier), "'%s' is not a legal CEL identifier", rootIdentifier); return new AutoValue_CelAttribute(ImmutableList.of(Qualifier.ofString(rootIdentifier))); } /** * Attempts to parse a dot qualified identifier into a CEL attribute. * * @throws IllegalArgumentException if qualifiedIdentifier isn't a legal qualified identifier. * Note: this is intended for use with reference names in a checked CEL expression -- it does * not check for some edge cases (e.g. reserved words). */ public static CelAttribute fromQualifiedIdentifier(String qualifiedIdentifier) { ImmutableList.Builder qualifiers = ImmutableList.builder(); Splitter.on(".") .split(qualifiedIdentifier) .forEach((element) -> qualifiers.add(Qualifier.ofString(element))); return new AutoValue_CelAttribute(qualifiers.build()); } /** The list of qualifiers representing the select path for this attribute. */ public abstract ImmutableList qualifiers(); /** * Creates a new attribute that is more qualified (has an additional select or index operation) * than the receiver. */ public CelAttribute qualify(Qualifier qualifier) { Preconditions.checkArgument( qualifier.kind() != Qualifier.Kind.WILD_CARD, "Wildcards are not permitted for attributes."); // To simplify client code, qualifying the empty singleton is still empty. if (qualifiers().isEmpty()) { return EMPTY; } return new AutoValue_CelAttribute( ImmutableList.builder().addAll(qualifiers()).add(qualifier).build()); } @Override public final String toString() { if (this.equals(EMPTY)) { return ""; } Preconditions.checkState( !qualifiers().isEmpty() && qualifiers().get(0).kind() == Qualifier.Kind.AS_STRING, "CelAttribute must have a root qualifier that is a legal identifier"); StringBuilder cname = new StringBuilder(qualifiers().get(0).asString()); for (Qualifier qualifier : qualifiers().subList(1, qualifiers().size())) { if (qualifier.kind() == Qualifier.Kind.AS_STRING && Qualifier.isLegalIdentifier(qualifier)) { cname.append(".").append(qualifier.asString()); } else { cname.append(qualifier.toIndexFormat()); } } return cname.toString(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy