Commit e7289923 authored by cdanger's avatar cdanger

- Update to new PDP API using java.util.Optional when relevant:

	- Change of type in AttributeGUID constructor's issuer parameter from
String to Optional <String>
	- Change of type in StatusHelper constructor's message and detail
parameters, from String to Optional<String>
	- Change of type returned by Datatype#getTypeParameter(): Datatype<?>
-> Optional<Datatype<?>>
parent 4f69942a
......@@ -42,7 +42,7 @@
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>${artifactId.prefix}-core-pdp-api</artifactId>
<version>9.0.0</version>
<version>9.0.1-SNAPSHOT</version>
</dependency>
<!-- /Authzforce dependencies -->
......
......@@ -27,6 +27,7 @@ import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.xml.bind.JAXBException;
......@@ -111,7 +112,7 @@ public final class BasePdpEngine implements CloseablePDP<ImmutablePdpDecisionReq
* Indeterminate response iff CombinedDecision element not supported because the request parser does not support any scheme from MultipleDecisionProfile section 2.
*/
private static final Response UNSUPPORTED_COMBINED_DECISION_RESPONSE = new Response(Collections.<Result> singletonList(new Result(DecisionType.INDETERMINATE, new StatusHelper(
StatusHelper.STATUS_SYNTAX_ERROR, "Unsupported feature: CombinedDecision='true'"), null, null, null, null)));
StatusHelper.STATUS_SYNTAX_ERROR, Optional.of("Unsupported feature: CombinedDecision='true'")), null, null, null, null)));
private interface StandardEnvironmentAttributeIssuer
{
......@@ -207,7 +208,7 @@ public final class BasePdpEngine implements CloseablePDP<ImmutablePdpDecisionReq
/*
* Put the non-issued version of the attribute first
*/
final AttributeGUID nonIssuedAttributeGUID = new AttributeGUID(attributeGUID.getCategory(), null, attributeGUID.getId());
final AttributeGUID nonIssuedAttributeGUID = new AttributeGUID(attributeGUID.getCategory(), Optional.empty(), attributeGUID.getId());
super.putNamedAttributeIfAbsent(nonIssuedAttributeGUID, attributeValues);
return super.putNamedAttributeIfAbsent(attributeGUID, attributeValues);
}
......@@ -277,8 +278,8 @@ public final class BasePdpEngine implements CloseablePDP<ImmutablePdpDecisionReq
private static final IndeterminateEvaluationException INDETERMINATE_EVALUATION_EXCEPTION = new IndeterminateEvaluationException("Internal error in decision cache: null result",
StatusHelper.STATUS_PROCESSING_ERROR);
private static final Result INVALID_DECISION_CACHE_RESULT = new Result(DecisionType.INDETERMINATE, new StatusHelper(StatusHelper.STATUS_PROCESSING_ERROR, "Internal error"), null, null, null,
null);
private static final Result INVALID_DECISION_CACHE_RESULT = new Result(DecisionType.INDETERMINATE, new StatusHelper(StatusHelper.STATUS_PROCESSING_ERROR, Optional.of("Internal error")), null,
null, null, null);
private final DecisionCache decisionCache;
......
......@@ -20,6 +20,7 @@ package org.ow2.authzforce.core.pdp.impl;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
......@@ -57,7 +58,7 @@ public class ModularAttributeProvider implements AttributeProvider
@Override
public void process(final AttributeGUID attributeGUID, final Bag<?> result, final EvaluationContext context)
{
if (attributeGUID.getIssuer() == null)
if (!attributeGUID.getIssuer().isPresent())
{
// Attribute already without Issuer -> nothing to copy
return;
......@@ -65,7 +66,7 @@ public class ModularAttributeProvider implements AttributeProvider
/*
* Attribute with Issuer -> make Issuer-less copy and put same result in context for match by Issuer-less AttributeDesignator
*/
final AttributeGUID issuerLessAttributeGUID = new AttributeGUID(attributeGUID.getCategory(), null, attributeGUID.getId());
final AttributeGUID issuerLessAttributeGUID = new AttributeGUID(attributeGUID.getCategory(), Optional.empty(), attributeGUID.getId());
/*
* Cache the attribute value(s) for the issuer-less attribute in context in case there is a matching Issuer-less AttributeDesignator to evaluate
*/
......
......@@ -20,10 +20,11 @@ package org.ow2.authzforce.core.pdp.impl;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import org.ow2.authzforce.core.pdp.api.AttributeGUID;
import org.ow2.authzforce.xacml.identifiers.XACMLAttributeId;
import org.ow2.authzforce.xacml.identifiers.XACMLAttributeCategory;
import org.ow2.authzforce.xacml.identifiers.XACMLAttributeId;
import com.google.common.collect.Maps;
......@@ -38,17 +39,17 @@ public enum StandardEnvironmentAttribute
/**
* urn:oasis:names:tc:xacml:1.0:environment:current-time
*/
CURRENT_TIME(new AttributeGUID(XACMLAttributeCategory.XACML_3_0_ENVIRONMENT.value(), null, XACMLAttributeId.XACML_1_0_ENVIRONMENT_CURRENT_TIME.value())),
CURRENT_TIME(new AttributeGUID(XACMLAttributeCategory.XACML_3_0_ENVIRONMENT.value(), Optional.empty(), XACMLAttributeId.XACML_1_0_ENVIRONMENT_CURRENT_TIME.value())),
/**
* urn:oasis:names:tc:xacml:1.0:environment:current-date
*/
CURRENT_DATE(new AttributeGUID(XACMLAttributeCategory.XACML_3_0_ENVIRONMENT.value(), null, XACMLAttributeId.XACML_1_0_ENVIRONMENT_CURRENT_DATE.value())),
CURRENT_DATE(new AttributeGUID(XACMLAttributeCategory.XACML_3_0_ENVIRONMENT.value(), Optional.empty(), XACMLAttributeId.XACML_1_0_ENVIRONMENT_CURRENT_DATE.value())),
/**
* urn:oasis:names:tc:xacml:1.0:environment:current-dateTime
*/
CURRENT_DATETIME(new AttributeGUID(XACMLAttributeCategory.XACML_3_0_ENVIRONMENT.value(), null, XACMLAttributeId.XACML_1_0_ENVIRONMENT_CURRENT_DATETIME.value()));
CURRENT_DATETIME(new AttributeGUID(XACMLAttributeCategory.XACML_3_0_ENVIRONMENT.value(), Optional.empty(), XACMLAttributeId.XACML_1_0_ENVIRONMENT_CURRENT_DATETIME.value()));
private final AttributeGUID attributeGUID;
......
......@@ -18,6 +18,8 @@
*/
package org.ow2.authzforce.core.pdp.impl.combining;
import java.util.Optional;
import javax.xml.bind.JAXBElement;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.DecisionType;
......@@ -55,8 +57,8 @@ final class OnlyOneApplicableCombiningAlg extends BaseCombiningAlg<PolicyEvaluat
private Evaluator(final String algId, final Iterable<? extends PolicyEvaluator> policyElements)
{
super(policyElements);
this.tooManyApplicablePoliciesIndeterminateResult = ExtendedDecisions.newIndeterminate(DecisionType.INDETERMINATE, new StatusHelper(StatusHelper.STATUS_PROCESSING_ERROR,
"Too many (more than one) applicable policies for algorithm: " + algId));
this.tooManyApplicablePoliciesIndeterminateResult = ExtendedDecisions.newIndeterminate(DecisionType.INDETERMINATE,
new StatusHelper(StatusHelper.STATUS_PROCESSING_ERROR, Optional.of("Too many (more than one) applicable policies for algorithm: " + algId)));
}
@Override
......
......@@ -57,10 +57,7 @@ import org.ow2.authzforce.core.pdp.api.value.Datatype;
*/
public final class AttributeDesignatorExpression<AV extends AttributeValue> implements Expression<Bag<AV>>
{
private static final IllegalArgumentException NULL_CATEGORY_EXCEPTION = new IllegalArgumentException("Undefined attribute designator category");
private static final IllegalArgumentException NULL_DATATYPE_EXCEPTION = new IllegalArgumentException("Undefined attribute designator datatype");
private static final IllegalArgumentException NULL_ATTRIBUTE_ID_EXCEPTION = new IllegalArgumentException("Undefined attribute designator AttribtueId");
private static final IllegalArgumentException NULL_ATTRIBUTE_Provider_EXCEPTION = new IllegalArgumentException("Undefined attribute Provider");
private static final IllegalArgumentException NULL_ATTRIBUTE_PROVIDER_EXCEPTION = new IllegalArgumentException("Undefined attribute Provider");
private static final UnsupportedOperationException UNSUPPORTED_OPERATION_EXCEPTION = new UnsupportedOperationException();
private final transient AttributeGUID attrGUID;
......@@ -91,35 +88,19 @@ public final class AttributeDesignatorExpression<AV extends AttributeValue> impl
* expected datatype of the result of evaluating this AttributeDesignator ( {@code AV is the expected type of every element in the bag})
* @param attrProvider
* Attribute Provider responsible for finding the attribute designated by this in a given evaluation context at runtime
* @throws IllegalArgumentException
* if {@code attrDesignator.getCategory() == null || attrDesignator.getAttributeId() == null}
*/
public AttributeDesignatorExpression(final AttributeDesignatorType attrDesignator, final BagDatatype<AV> resultDatatype, final AttributeProvider attrProvider)
{
final String categoryURI = attrDesignator.getCategory();
if (categoryURI == null)
{
throw NULL_CATEGORY_EXCEPTION;
}
final String datatypeURI = attrDesignator.getDataType();
if (datatypeURI == null)
{
throw NULL_DATATYPE_EXCEPTION;
}
final String id = attrDesignator.getAttributeId();
if (id == null)
{
throw NULL_ATTRIBUTE_ID_EXCEPTION;
}
if (attrProvider == null)
{
throw NULL_ATTRIBUTE_Provider_EXCEPTION;
throw NULL_ATTRIBUTE_PROVIDER_EXCEPTION;
}
this.attrGUID = new AttributeGUID(categoryURI, attrDesignator.getIssuer(), id);
this.returnType = resultDatatype;
this.attrProvider = attrProvider;
this.attrGUID = new AttributeGUID(attrDesignator);
this.returnType = resultDatatype;
// error messages/exceptions
final String missingAttributeMessage = this + " not found in context";
......
......@@ -24,6 +24,7 @@ import java.util.Collections;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
......@@ -311,7 +312,7 @@ public final class AttributeSelectorExpression<AV extends AttributeValue> implem
throw NULL_ATTRIBUTE_Provider_BUT_NON_NULL_CONTEXT_SELECTOR_ID_EXCEPTION;
}
final AttributeGUID contextSelectorGUID = new AttributeGUID(attributeSelectorId.getCategory(), null, contextSelectorId);
final AttributeGUID contextSelectorGUID = new AttributeGUID(attributeSelectorId.getCategory(), Optional.empty(), contextSelectorId);
final String missingContextSelectorAttributeExceptionMessage = this + ": No value found for attribute designated by Category=" + attributeCategory + " and ContextSelectorId="
+ contextSelectorId;
final IndeterminateEvaluationException missingAttributeForUnknownReasonException = new IndeterminateEvaluationException(missingAttributeMessage + " for unknown reason",
......@@ -432,19 +433,14 @@ public final class AttributeSelectorExpression<AV extends AttributeValue> implem
final AttributeValue attrVal;
try
{
attrVal = attrFactory.getInstance(jaxbAttrVal.getContent(), jaxbAttrVal.getOtherAttributes(),
this.xpathCompiler);
attrVal = attrFactory.getInstance(jaxbAttrVal.getContent(), jaxbAttrVal.getOtherAttributes(), this.xpathCompiler);
}
catch (final IllegalArgumentException e)
{
final String contextSelectorId = attributeSelectorId.getContextSelectorId();
throw new IndeterminateEvaluationException(this + ": Error creating attribute value of type '"
+ attributeDatatype + "' from result #" + xpathEvalResultItemIndex
+ " of evaluating XPath against XML node from Content of Attributes Category='"
+ attributeSelectorId.getCategory() + "'"
+ (contextSelectorId == null ? ""
: " selected by ContextSelectorId='" + contextSelectorId + "'")
+ ": " + xpathEvalResultItem, StatusHelper.STATUS_SYNTAX_ERROR, e);
throw new IndeterminateEvaluationException(this + ": Error creating attribute value of type '" + attributeDatatype + "' from result #" + xpathEvalResultItemIndex
+ " of evaluating XPath against XML node from Content of Attributes Category='" + attributeSelectorId.getCategory() + "'"
+ (contextSelectorId == null ? "" : " selected by ContextSelectorId='" + contextSelectorId + "'") + ": " + xpathEvalResultItem, StatusHelper.STATUS_SYNTAX_ERROR, e);
}
resultBag.add(attributeDatatype.cast(attrVal));
......
......@@ -65,7 +65,7 @@ final class MapFunctionFactory extends GenericHigherOrderFunctionFactory
private final String indeterminateSubFuncEvalMessagePrefix;
private Call(final String functionId, final Datatype<Bag<SUB_RETURN>> returnType, final FirstOrderFunction<SUB_RETURN> subFunction, final List<Expression<?>> primitiveInputs,
final Expression<?> lastInputBag)
final Expression<? extends Bag<?>> lastInputBag)
{
super(functionId, returnType, subFunction, primitiveInputs, lastInputBag);
this.returnBagElementType = subFunction.getReturnType();
......@@ -108,7 +108,7 @@ final class MapFunctionFactory extends GenericHigherOrderFunctionFactory
@Override
protected OneBagOnlyHigherOrderFunction.Call<Bag<SUB_RETURN_T>, SUB_RETURN_T> newFunctionCall(final FirstOrderFunction<SUB_RETURN_T> subFunc, final List<Expression<?>> primitiveInputs,
final Expression<?> lastInputBag)
final Expression<? extends Bag<?>> lastInputBag)
{
return new Call<>(this.getId(), this.getReturnType(), subFunc, primitiveInputs, lastInputBag);
}
......
......@@ -26,6 +26,7 @@ import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Optional;
import org.ow2.authzforce.core.pdp.api.EvaluationContext;
import org.ow2.authzforce.core.pdp.api.IndeterminateEvaluationException;
......@@ -53,18 +54,15 @@ import org.ow2.authzforce.core.pdp.api.value.Value;
final class StandardHigherOrderBagFunctions
{
private static abstract class BooleanHigherOrderBagFunction
extends HigherOrderBagFunction<BooleanValue, BooleanValue>
private static abstract class BooleanHigherOrderBagFunction extends HigherOrderBagFunction<BooleanValue, BooleanValue>
{
protected final String subFunctionCallErrorMessagePrefix;
private BooleanHigherOrderBagFunction(final String functionId)
{
super(functionId, StandardDatatypes.BOOLEAN_FACTORY.getDatatype(),
StandardDatatypes.BOOLEAN_FACTORY.getDatatype());
this.subFunctionCallErrorMessagePrefix = "Function " + functionId
+ ": Error evaluating sub-function with arguments (evaluated to): ";
super(functionId, StandardDatatypes.BOOLEAN_FACTORY.getDatatype(), StandardDatatypes.BOOLEAN_FACTORY.getDatatype());
this.subFunctionCallErrorMessagePrefix = "Function " + functionId + ": Error evaluating sub-function with arguments (evaluated to): ";
}
}
......@@ -74,8 +72,7 @@ final class StandardHigherOrderBagFunctions
*/
private static abstract class BooleanHigherOrderTwoBagFunction extends BooleanHigherOrderBagFunction
{
private final IllegalArgumentException invalidLastArgTypeException = new IllegalArgumentException(
"Function" + this + ": Invalid last argument type: primitive (not a bag). Required: a bag");
private final IllegalArgumentException invalidLastArgTypeException = new IllegalArgumentException("Function" + this + ": Invalid last argument type: primitive (not a bag). Required: a bag");
private BooleanHigherOrderTwoBagFunction(final String functionId)
{
......@@ -87,8 +84,7 @@ final class StandardHigherOrderBagFunctions
{
if (numInputs != 3)
{
throw new IllegalArgumentException(
"Function " + this + ": Invalid number of arguments (" + numInputs + "). Required: 3");
throw new IllegalArgumentException("Function " + this + ": Invalid number of arguments (" + numInputs + "). Required: 3");
}
}
......@@ -100,20 +96,21 @@ final class StandardHigherOrderBagFunctions
private final Expression<? extends Bag<?>> bagArgExpr0;
private final Expression<? extends Bag<?>> bagArgExpr1;
private Call(final String functionId, final FirstOrderFunction<BooleanValue> subFunc,
final Expression<? extends Bag<?>> input0, final Expression<? extends Bag<?>> input1)
private Call(final String functionId, final FirstOrderFunction<BooleanValue> subFunc, final Expression<? extends Bag<?>> input0, final Expression<? extends Bag<?>> input1)
{
final Datatype<?>[] subFuncArgTypes = { input0.getReturnType().getTypeParameter(),
input1.getReturnType().getTypeParameter() };
this.subFuncCall = subFunc.newCall(Collections.<Expression<?>>emptyList(), subFuncArgTypes);
final Optional<Datatype<?>> bagElementType0 = input0.getReturnType().getTypeParameter();
final Optional<Datatype<?>> bagElementType1 = input1.getReturnType().getTypeParameter();
assert bagElementType0.isPresent() && bagElementType1.isPresent();
final Datatype<?>[] subFuncArgTypes = { bagElementType0.get(), bagElementType1.get() };
this.subFuncCall = subFunc.newCall(Collections.<Expression<?>> emptyList(), subFuncArgTypes);
this.bagArgExpr0 = input0;
this.bagArgExpr1 = input1;
this.errorEvalArg1Message = "Function " + functionId + ": Error evaluating second arg #1";
this.errorEvalArg2Message = "Function " + functionId + ": Error evaluating arg #2";
}
protected abstract BooleanValue evaluate(Bag<?> bag0, Bag<?> bag1, EvaluationContext context)
throws IndeterminateEvaluationException;
protected abstract BooleanValue evaluate(Bag<?> bag0, Bag<?> bag1, EvaluationContext context) throws IndeterminateEvaluationException;
@Override
public final BooleanValue evaluate(final EvaluationContext context) throws IndeterminateEvaluationException
......@@ -125,14 +122,12 @@ final class StandardHigherOrderBagFunctions
}
catch (final IndeterminateEvaluationException e)
{
throw new IndeterminateEvaluationException(errorEvalArg1Message,
StatusHelper.STATUS_PROCESSING_ERROR);
throw new IndeterminateEvaluationException(errorEvalArg1Message, StatusHelper.STATUS_PROCESSING_ERROR);
}
/*
* If result bag empty, returns False as there will be no possibility for a Predicate that is "True".
* AttributeDesignator/AttributeSelector with MustBePresent=False may evaluate to empty bags
* (Indeterminate Exception if MustBePresent=True). empty bag.
* If result bag empty, returns False as there will be no possibility for a Predicate that is "True". AttributeDesignator/AttributeSelector with MustBePresent=False may evaluate to
* empty bags (Indeterminate Exception if MustBePresent=True). empty bag.
*/
if (bag0.isEmpty())
{
......@@ -146,8 +141,7 @@ final class StandardHigherOrderBagFunctions
}
catch (final IndeterminateEvaluationException e)
{
throw new IndeterminateEvaluationException(errorEvalArg2Message,
StatusHelper.STATUS_PROCESSING_ERROR);
throw new IndeterminateEvaluationException(errorEvalArg2Message, StatusHelper.STATUS_PROCESSING_ERROR);
}
if (bag1.isEmpty())
......@@ -166,19 +160,17 @@ final class StandardHigherOrderBagFunctions
}
protected abstract BooleanValue evaluate(FirstOrderFunctionCall<BooleanValue> subFunctionCall, Bag<?> bag0,
Bag<?> bag1, EvaluationContext context) throws IndeterminateEvaluationException;
protected abstract BooleanValue evaluate(FirstOrderFunctionCall<BooleanValue> subFunctionCall, Bag<?> bag0, Bag<?> bag1, EvaluationContext context) throws IndeterminateEvaluationException;
@Override
protected final FunctionCall<BooleanValue> createFunctionCallFromSubFunction(
final FirstOrderFunction<BooleanValue> subFunc, final List<Expression<?>> inputsAfterSubFunc)
protected final FunctionCall<BooleanValue> createFunctionCallFromSubFunction(final FirstOrderFunction<BooleanValue> subFunc, final List<Expression<?>> inputsAfterSubFunc)
{
final Iterator<Expression<?>> inputsAfterSubfuncIterator = inputsAfterSubFunc.iterator();
while (inputsAfterSubfuncIterator.hasNext())
{
// all must be bag
if (inputsAfterSubfuncIterator.next().getReturnType().getTypeParameter() == null)
if (!inputsAfterSubfuncIterator.next().getReturnType().getTypeParameter().isPresent())
{
throw invalidLastArgTypeException;
}
......@@ -190,8 +182,7 @@ final class StandardHigherOrderBagFunctions
{
@Override
protected BooleanValue evaluate(final Bag<?> bag0, final Bag<?> bag1, final EvaluationContext context)
throws IndeterminateEvaluationException
protected BooleanValue evaluate(final Bag<?> bag0, final Bag<?> bag1, final EvaluationContext context) throws IndeterminateEvaluationException
{
return BooleanHigherOrderTwoBagFunction.this.evaluate(subFuncCall, bag0, bag1, context);
}
......@@ -203,18 +194,13 @@ final class StandardHigherOrderBagFunctions
* one-bag-only functions (only last arg is bag): any-of, all-of, map.
*
*/
static abstract class OneBagOnlyHigherOrderFunction<RETURN_T extends Value, SUB_RETURN_T extends AttributeValue>
extends HigherOrderBagFunction<RETURN_T, SUB_RETURN_T>
static abstract class OneBagOnlyHigherOrderFunction<RETURN_T extends Value, SUB_RETURN_T extends AttributeValue> extends HigherOrderBagFunction<RETURN_T, SUB_RETURN_T>
{
private final String invalidArityMsgPrefix = "Function " + this
+ ": Invalid number of arguments: expected: >= 2; actual: ";
private final String unexpectedBagInputErrorMsg = " Function " + this
+ ": Invalid type (expected: primitive, actual: bag) of argument #";
private final IllegalArgumentException invalidLastArgTypeException = new IllegalArgumentException(
this + ": Invalid last argument type: expected: bag; actual: primitive");
static abstract class Call<RETURN extends Value, SUB_RETURN extends AttributeValue>
implements FunctionCall<RETURN>
private final String invalidArityMsgPrefix = "Function " + this + ": Invalid number of arguments: expected: >= 2; actual: ";
private final String unexpectedBagInputErrorMsg = " Function " + this + ": Invalid type (expected: primitive, actual: bag) of argument #";
private final IllegalArgumentException invalidLastArgTypeException = new IllegalArgumentException(this + ": Invalid last argument type: expected: bag; actual: primitive");
static abstract class Call<RETURN extends Value, SUB_RETURN extends AttributeValue> implements FunctionCall<RETURN>
{
private final String errorEvalLastArgMsg;
protected final FirstOrderFunctionCall<SUB_RETURN> subFuncCall;
......@@ -222,51 +208,42 @@ final class StandardHigherOrderBagFunctions
private final BagDatatype<?> lastArgBagDatatype;
private final Datatype<RETURN> returnType;
protected Call(final String functionId, final Datatype<RETURN> returnType,
final FirstOrderFunction<SUB_RETURN> subFunction, final List<Expression<?>> primitiveInputs,
final Expression<?> lastInputBag)
protected Call(final String functionId, final Datatype<RETURN> returnType, final FirstOrderFunction<SUB_RETURN> subFunction, final List<Expression<?>> primitiveInputs,
final Expression<? extends Bag<?>> lastInputBag)
{
final Datatype<?> lastArgExpDatatype = lastInputBag.getReturnType();
if (lastArgExpDatatype.getTypeParameter() == null)
{
throw new IllegalArgumentException("Function " + functionId
+ ": last argument expression's return type: expected: Bag; actual: " + lastArgExpDatatype);
}
final Datatype<? extends Bag<?>> lastArgExpDatatype = lastInputBag.getReturnType();
/*
* BagDatatype is expected to be the only Datatype implementation for Datatype<Bag<?>>
*/
assert lastArgExpDatatype instanceof BagDatatype;
lastArgBagExpr = lastInputBag;
// Bag.Datatype is the only Datatype implementation for Datatype<Bag<?>>
lastArgBagDatatype = (BagDatatype<?>) lastArgExpDatatype;
lastArgBagExpr = lastInputBag;
/*
* The actual expression passed as last argument to the sub-function is not yet known; but we know the
* expected datatype is the type of each element lastInputBag's evaluation result bag, therefore the
* element datatype, i.e. type parameter to the returned bag datatype
* The actual expression passed as last argument to the sub-function is not yet known; but we know the expected datatype is the type of each element lastInputBag's evaluation result
* bag, therefore the element datatype, i.e. type parameter to the returned bag datatype
*/
this.subFuncCall = subFunction.newCall(primitiveInputs,
lastInputBag.getReturnType().getTypeParameter());
this.subFuncCall = subFunction.newCall(primitiveInputs, lastArgBagDatatype.getElementType());
this.errorEvalLastArgMsg = "Function " + functionId + ": Error evaluating last arg (bag)";
this.returnType = returnType;
}
/**
* Evaluates the function call. The evaluation combines the results of <i>eval<sub>i</sub></i> for <i>i</i>
* in [0.. {@code lastArgBag.size()-1}], where <i>eval<sub>i</sub></i> is the evaluation of the sub-function
* (in this higher-order function call, i.e. first arg) with the n-1 first arguments defined in this
* function call - n being the arity of the sub-function - and the n-th/last argument is the <i>i</i>-th
* value in {@code lastArgBag} in parameter
* Evaluates the function call. The evaluation combines the results of <i>eval<sub>i</sub></i> for <i>i</i> in [0.. {@code lastArgBag.size()-1}], where <i>eval<sub>i</sub></i> is the
* evaluation of the sub-function (in this higher-order function call, i.e. first arg) with the n-1 first arguments defined in this function call - n being the arity of the sub-function -
* and the n-th/last argument is the <i>i</i>-th value in {@code lastArgBag} in parameter
*
* @param lastArgBag
* the bag of which each value is used successively as the last argument to the sub-function for
* each sub-function evaluation
* the bag of which each value is used successively as the last argument to the sub-function for each sub-function evaluation
* @param context
* evaluation context in which arguments are evaluated
* @return result combined result (depending on the implementation)
* @throws IndeterminateEvaluationException
* if any error occurred during evaluation
*/
protected abstract RETURN evaluate(Bag<?> lastArgBag, EvaluationContext context)
throws IndeterminateEvaluationException;
protected abstract RETURN evaluate(Bag<?> lastArgBag, EvaluationContext context) throws IndeterminateEvaluationException;
@Override
public final RETURN evaluate(final EvaluationContext context) throws IndeterminateEvaluationException
......@@ -294,8 +271,7 @@ final class StandardHigherOrderBagFunctions
/*
* 'protected' because used by separate MapFunction class
*/
protected OneBagOnlyHigherOrderFunction(final String functionName, final Datatype<RETURN_T> returnType,
final Datatype<SUB_RETURN_T> subFunctionReturnType)
protected OneBagOnlyHigherOrderFunction(final String functionName, final Datatype<RETURN_T> returnType, final Datatype<SUB_RETURN_T> subFunctionReturnType)
{
super(functionName, returnType, subFunctionReturnType);
}
......@@ -320,19 +296,17 @@ final class StandardHigherOrderBagFunctions
* last argument - bag (datatype already checked)
* @return function call
*/
protected abstract Call<RETURN_T, SUB_RETURN_T> newFunctionCall(FirstOrderFunction<SUB_RETURN_T> subFunc,
List<Expression<?>> primitiveInputs, Expression<?> lastInputBag);
protected abstract Call<RETURN_T, SUB_RETURN_T> newFunctionCall(FirstOrderFunction<SUB_RETURN_T> subFunc, List<Expression<?>> primitiveInputs, Expression<? extends Bag<?>> lastInputBag);
@Override
protected final FunctionCall<RETURN_T> createFunctionCallFromSubFunction(
final FirstOrderFunction<SUB_RETURN_T> subFunc, final List<Expression<?>> inputsAfterSubFunc)
protected final FunctionCall<RETURN_T> createFunctionCallFromSubFunction(final FirstOrderFunction<SUB_RETURN_T> subFunc, final List<Expression<?>> inputsAfterSubFunc)
{
final Iterator<Expression<?>> inputsAfterSubfuncIterator = inputsAfterSubFunc.iterator();
// inputs that we can parse/validate for the sub-function are the primitive inputs, i.e.
// all except last one which is a bag
final List<Expression<?>> primitiveInputs = new ArrayList<>();
int argIndex = 0;
Expression<?> lastInputBag = null;
Expression<? extends Bag<?>> lastInputBag = null;
boolean hasNextInput = true;
while (hasNextInput)
{
......@@ -340,11 +314,13 @@ final class StandardHigherOrderBagFunctions
argIndex++;
hasNextInput = inputsAfterSubfuncIterator.hasNext();
final Datatype<?> inputType = input.getReturnType();
final Optional<Datatype<?>> typeParam = inputType.getTypeParameter();
if (hasNextInput)
{
// not the last input, must be primitive
if (inputType.getTypeParameter() != null)
if (typeParam.isPresent())
{
// not primitive but generic
throw new IllegalArgumentException(unexpectedBagInputErrorMsg + argIndex);
}
......@@ -353,12 +329,16 @@ final class StandardHigherOrderBagFunctions
else
{
// last input, must be a bag
if (inputType.getTypeParameter() == null)
if (!typeParam.isPresent())
{
// primitive
throw invalidLastArgTypeException;
}
lastInputBag = input;
/*
* BagDatatype expected to be the only bag Datatype
*/
lastInputBag = (Expression<? extends Bag<?>>) input;
}
}
......@@ -377,8 +357,7 @@ final class StandardHigherOrderBagFunctions
private CallFactory(final String functionId)
{
this.functionId = functionId;
this.subFuncCallWithLastArgErrMsgPrefix = "Function " + functionId
+ ": Error calling sub-function (specified as first argument) with last arg=";
this.subFuncCallWithLastArgErrMsgPrefix = "Function " + functionId + ": Error calling sub-function (specified as first argument) with last arg=";
}
/**
......@@ -391,25 +370,21 @@ final class StandardHigherOrderBagFunctions
protected abstract BooleanValue getFinalResult(BooleanValue subFunctionResult);
/**
* Get default final result of this higher-order function, i.e. the final result when
* {@link #getFinalResult(BooleanValue)} returned null for all sub-function evaluations (one per arg in the
* bag)
* Get default final result of this higher-order function, i.e. the final result when {@link #getFinalResult(BooleanValue)} returned null for all sub-function evaluations (one per arg in
* the bag)
*
* @return default final result
*/
protected abstract BooleanValue defaultFinalResult();
private OneBagOnlyHigherOrderFunction.Call<BooleanValue, BooleanValue> getInstance(
final FirstOrderFunction<BooleanValue> subFunc, final List<Expression<?>> primitiveInputs,
final Expression<?> lastInputBag)
private OneBagOnlyHigherOrderFunction.Call<BooleanValue, BooleanValue> getInstance(final FirstOrderFunction<BooleanValue> subFunc, final List<Expression<?>> primitiveInputs,
final Expression<? extends Bag<?>> lastInputBag)
{
return new OneBagOnlyHigherOrderFunction.Call<BooleanValue, BooleanValue>(functionId,
StandardDatatypes.BOOLEAN_FACTORY.getDatatype(), subFunc, primitiveInputs, lastInputBag)
return new OneBagOnlyHigherOrderFunction.Call<BooleanValue, BooleanValue>(functionId, StandardDatatypes.BOOLEAN_FACTORY.getDatatype(), subFunc, primitiveInputs, lastInputBag)
{
@Override
protected BooleanValue evaluate(final Bag<?> lastArgBag, final EvaluationContext context)
throws IndeterminateEvaluationException
protected BooleanValue evaluate(final Bag<?> lastArgBag, final EvaluationContext context) throws IndeterminateEvaluationException
{
for (final AttributeValue attrVal : lastArgBag)
{
......@@ -420,8 +395,7 @@ final class StandardHigherOrderBagFunctions
}
catch (final IndeterminateEvaluationException e)
{
throw new IndeterminateEvaluationException(subFuncCallWithLastArgErrMsgPrefix + attrVal,
e.getStatusCode(), e);
throw new IndeterminateEvaluationException(subFuncCallWithLastArgErrMsgPrefix + attrVal, e.getStatusCode(), e);
}
final BooleanValue finalResult = getFinalResult(subResult);
......@@ -442,15 +416,13 @@ final class StandardHigherOrderBagFunctions
protected BooleanOneBagOnlyFunction(final String functionId, final CallFactory functionCallFactory)
{
super(functionId, StandardDatatypes.BOOLEAN_FACTORY.getDatatype(),
StandardDatatypes.BOOLEAN_FACTORY.getDatatype());
super(functionId, StandardDatatypes.BOOLEAN_FACTORY.getDatatype(), StandardDatatypes.BOOLEAN_FACTORY.getDatatype());
this.funcCallFactory = functionCallFactory;
}
@Override
protected OneBagOnlyHigherOrderFunction.Call<BooleanValue, BooleanValue> newFunctionCall(
final FirstOrderFunction<BooleanValue> subFunc, final List<Expression<?>> primitiveInputs,
final Expression<?> lastInputBag)
protected OneBagOnlyHigherOrderFunction.Call<BooleanValue, BooleanValue> newFunctionCall(final FirstOrderFunction<BooleanValue> subFunc, final List<Expression<?>> primitiveInputs,
final Expression<? extends Bag<?>> lastInputBag)
{
return funcCallFactory.getInstance(subFunc, primitiveInputs, lastInputBag);
}
......@@ -535,8 +507,7 @@ final class StandardHigherOrderBagFunctions
AnyOfAny(final String functionId)
{
super(functionId);
this.subFuncArgEvalErrMsg = "Function " + functionId
+ ": Error evaluating one of the arguments after sub-function";
this.subFuncArgEvalErrMsg = "Function " + functionId + ": Error evaluating one of the arguments after sub-function";
}
@Override
......@@ -544,14 +515,12 @@ final class StandardHigherOrderBagFunctions
{
if (numInputs < 2)
{
throw new IllegalArgumentException(
"Function " + this + ": Invalid number of arguments (" + numInputs + "). Required: >= 2");
throw new IllegalArgumentException("Function " + this + ": Invalid number of arguments (" + numInputs + "). Required: >= 2");
}
}
@Override
protected FunctionCall<BooleanValue> createFunctionCallFromSubFunction(
final FirstOrderFunction<BooleanValue> subFunc, final List<Expression<?>> inputsAfterSubFunc)
protected FunctionCall<BooleanValue> createFunctionCallFromSubFunction(final FirstOrderFunction<BooleanValue> subFunc, final List<Expression<?>> inputsAfterSubFunc)
{
return new AnyOfAnyFunctionCall(subFunc, inputsAfterSubFunc);
}
......@@ -562,14 +531,11 @@ final class StandardHigherOrderBagFunctions
private final int subFuncArity;
private final List<Expression<?>> inputsAfterSubFunc;
protected AnyOfAnyFunctionCall(final FirstOrderFunction<BooleanValue> subFunc,
final List<Expression<?>> inputsAfterSubFunc)
protected AnyOfAnyFunctionCall(final FirstOrderFunction<BooleanValue> subFunc, final List<Expression<?>> inputsAfterSubFunc)
{
/*
* According to spec of an-of-any function, the remaining arguments (inputsAfterSubFunc here) are either
* primitive data types or bags of primitive types. The expression SHALL be evaluated as if the function
* named in the <Function> argument (subFunc here) was applied between every tuple of the cross product
* on all bags and the primitive values.
* According to spec of an-of-any function, the remaining arguments (inputsAfterSubFunc here) are either primitive data types or bags of primitive types. The expression SHALL be
* evaluated as if the function named in the <Function> argument (subFunc here) was applied between every tuple of the cross product on all bags and the primitive values.
*/
this.subFuncArity = inputsAfterSubFunc.size();
final Datatype<?>[] subFuncArgTypes = new Datatype<?>[subFuncArity];
......@@ -578,22 +544,19 @@ final class StandardHigherOrderBagFunctions
{
final Datatype<?> inputDatatype = input.getReturnType();
/*
* Always primitive datatype used in the sub-function call (typeParameter of the datatype for a bag
* datatype, else the datatype itself (already primitive))
* Always primitive datatype are used in the sub-function call (typeParameter of the datatype if it is a generic/bag datatype, else the datatype itself (already primitive))
*/
subFuncArgTypes[i] = inputDatatype.getTypeParameter() == null ? inputDatatype
: inputDatatype.getTypeParameter();
final Optional<Datatype<?>> typeParam = inputDatatype.getTypeParameter();
subFuncArgTypes[i] = typeParam.orElse(inputDatatype);
i++;
}