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

com.sap.cloud.security.ams.dcl.client.el.Call Maven / Gradle / Ivy

The newest version!
/************************************************************************
 * © 2019-2024 SAP SE or an SAP affiliate company. All rights reserved. *
 ************************************************************************/
package com.sap.cloud.security.ams.dcl.client.el;

import static com.sap.cloud.security.ams.dcl.client.el.ELInternalTools.EMPTY_OBJECT_ARRAY;
import static com.sap.cloud.security.ams.dcl.client.el.ELInternalTools.copyArguments;
import static com.sap.cloud.security.ams.dcl.client.el.QualifiedNamesBuilder.globalParseQualifiedName;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.function.Consumer;

/**
 * Instances of this type are immutable and thread-safe.
 * 

* Any setter must return a new instance, if the state would change. In case of no change, it may return the same instance or create a new one. * * @apiNote {@code Call} is not to be extended by consumers. * @since 0.5 */ public class Call implements Expression, Iterable { @SuppressWarnings("java:S1214") public static interface Names { String AND = "and"; String OR = "or"; String IS_NULL = "is_null"; String IS_NOT_NULL = "is_not_null"; String LIKE = "like"; String NOT_LIKE = "not_like"; String IN = "in"; String NOT_IN = "not_in"; String LT = "lt"; String LE = "le"; String EQ = "eq"; String NE = "ne"; String GE = "ge"; String GT = "gt"; String BETWEEN = "between"; String NOT_BETWEEN = "not_between"; /** * RESTRICTED appears in DCN and is not present in evaluated filter clauses. * * @since 0.12.0 */ String RESTRICTED = "restricted"; /** * NOT_RESTRICTED appears in DCN and is not present in evaluated filter clauses. * * @since 0.12.0 */ String NOT_RESTRICTED = "not_restricted"; } /** * @since 0.12.0 */ @SuppressWarnings("java:S1214") public static interface QualifiedNames { QualifiedName AND = QualifiedName.create(Names.AND); QualifiedName OR = QualifiedName.create(Names.OR); QualifiedName IS_NULL = QualifiedName.create(Names.IS_NULL); QualifiedName IS_NOT_NULL = QualifiedName.create(Names.IS_NOT_NULL); QualifiedName LIKE = QualifiedName.create(Names.LIKE); QualifiedName NOT_LIKE = QualifiedName.create(Names.NOT_LIKE); QualifiedName IN = QualifiedName.create(Names.IN); QualifiedName NOT_IN = QualifiedName.create(Names.NOT_IN); QualifiedName LT = QualifiedName.create(Names.LT); QualifiedName LE = QualifiedName.create(Names.LE); QualifiedName EQ = QualifiedName.create(Names.EQ); QualifiedName NE = QualifiedName.create(Names.NE); QualifiedName GE = QualifiedName.create(Names.GE); QualifiedName GT = QualifiedName.create(Names.GT); QualifiedName BETWEEN = QualifiedName.create(Names.BETWEEN); QualifiedName NOT_BETWEEN = QualifiedName.create(Names.NOT_BETWEEN); QualifiedName RESTRICTED = QualifiedName.create(Names.RESTRICTED); QualifiedName NOT_RESTRICTED = QualifiedName.create(Names.NOT_RESTRICTED); } private final QualifiedName qualifiedName; private final Object[] args; private transient int hash; private transient volatile List argsList; // NOSONAR // Name must match SEGMENTS_LIST_UPDATER @SuppressWarnings("rawtypes") private static final AtomicReferenceFieldUpdater ARGS_LIST_UPDATER = // AtomicReferenceFieldUpdater.newUpdater(Call.class, List.class, "argsList"); private Call(Object[] args, QualifiedName qualifiedName) { this.qualifiedName = Objects.requireNonNull(qualifiedName); this.args = args; // NOSONAR } private Call(QualifiedName qualifiedName) { this(EMPTY_OBJECT_ARRAY, qualifiedName); } private Call(QualifiedName qualifiedName, Object argument) { this(new Object[] { argument }, qualifiedName); } private Call(QualifiedName qualifiedName, Object arg0, Object arg1) { this(new Object[] { arg0, arg1 }, qualifiedName); } private Call(QualifiedName qualifiedName, Object arg0, Object arg1, Object arg2) { this(new Object[] { arg0, arg1, arg2 }, qualifiedName); } protected Call(QualifiedName qualifiedName, Object[] args) { this(copyArguments(args), qualifiedName); } protected Call(Call other) { this.qualifiedName = other.qualifiedName; this.args = other.args; // NOSONAR this.hash = other.hash; this.argsList = other.argsList; } @Override public final int hashCode() { int h = hash; if (h == 0) { final int prime = 31; h = 1; h = prime * h + Arrays.hashCode(args); h = prime * h + qualifiedName.hashCode(); hash = h; } return h; } @Override public final boolean equals(Object obj) { if (this == obj) return true; if (obj instanceof Call) { Call other = (Call) obj; return hashCode() == other.hashCode() && qualifiedName.equals(other.qualifiedName) && Arrays.equals(args, other.args); } return false; } @Override public final void accept(Visitor visitor) { visitor.visit(this); } @Override public final Object accept(Transformer transformer) { return transformer.transform(this); } @Override public final Iterator iterator() { return args.length == 0 ? Collections.emptyIterator() : new ObjectArrayIterator(args); } public final String getName() { return qualifiedName.toEncodedString(); } /** * @return qualifiedName * @since 0.10 */ public final QualifiedName getQualifiedName() { return qualifiedName; } public final List getArguments() { List res = argsList; if (res != null) { return res; // NOSONAR } res = ELInternalTools.createListWithOwnership(args); return ARGS_LIST_UPDATER.compareAndSet(this, null, res) ? res : argsList; } public final Object getArgument(int index) { return args[index]; } public final int getArgumentCount() { return args.length; } /** * There is no guarantee for the returned string format. It is only for debugging and printing purpose. */ @Override public final String toString() { return ELTools.toString(this); } /** * Returns a new Call object, if the give name differs from the current one. Else it returns this. * * @param name * for the new Call object. Must not be null. * @return new Call object with changed name or this, if name does not differ */ public final Call setName(String name) { return getName().equals(name) ? this : new Call(args, globalParseQualifiedName(name)); } /** * Returns a new Call object, if the give name differs from the current one. Else it returns this. * * @param qualifiedName * for the new Call object. Must not be null. * @return new Call object with changed name or this, if name does not differ * @since 0.10 */ public final Call setQualifiedName(QualifiedName qualifiedName) { return this.qualifiedName.equals(qualifiedName) ? this : new Call(args, qualifiedName); } @Override public final void forEach(Consumer action) { Objects.requireNonNull(action); Object[] a = this.args; for (int i = 0, end = args.length; i < end; ++i) { action.accept(a[i]); } } // // // public static Call create(String name) { return new Call(globalParseQualifiedName(name)); } public static Call create(String name, Object arg0) { return new Call(globalParseQualifiedName(name), arg0); } public static Call create(String name, Object arg0, Object arg1) { return new Call(globalParseQualifiedName(name), arg0, arg1); } public static Call create(String name, Object arg0, Object arg1, Object arg2) { return new Call(globalParseQualifiedName(name), arg0, arg1, arg2); } public static Call create(String name, Object... args) { return new Call(globalParseQualifiedName(name), args); } // // Replaced in 0.12.0 with createFrom(QualifiedName name, Collection args) // // public static Call createFrom(String name, List args) { // return ELInternalTools.createCallFrom(name, args); // } /** * @param name * full qualified name for Call * @param args * call arguments. The call arguments are ordered in the iteration order over the collection. * @return create call instance * * @since 0.12.0 * */ public static Call createFrom(String name, Collection args) { return new Call(copyArguments(args), globalParseQualifiedName(name)); } public static Call createFrom(String name, Object[] args, int start, int end) { return new Call(copyArguments(args, start, end), globalParseQualifiedName(name)); } // // Since 0.10.0 // public static Call create(QualifiedName qualifiedName) { return new Call(qualifiedName); } public static Call create(QualifiedName qualifiedName, Object arg0) { return new Call(qualifiedName, arg0); } public static Call create(QualifiedName qualifiedName, Object arg0, Object arg1) { return new Call(qualifiedName, arg0, arg1); } public static Call create(QualifiedName qualifiedName, Object arg0, Object arg1, Object arg2) { return new Call(qualifiedName, arg0, arg1, arg2); } public static Call create(QualifiedName qualifiedName, Object... args) { return new Call(qualifiedName, args); } // // Replaced in 0.12.0 with createFrom(QualifiedName name, Collection args) // // public static Call createFrom(QualifiedName name, List args) { // return ELInternalTools.createCallFrom(name, args); // } /** * @param qualifiedName * full qualified name for Call * @param args * call arguments. The call arguments are ordered in the iteration order over the collection. * @return create call instance * * @since 0.12.0 * */ public static Call createFrom(QualifiedName qualifiedName, Collection args) { return new Call(copyArguments(args), qualifiedName); } public static Call createFrom(QualifiedName qualifiedName, Object[] args, int start, int end) { return new Call(copyArguments(args, start, end), qualifiedName); } }