| /******************************************************************************* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 |
| * |
| * http://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 org.apache.olingo.odata2.core.uri.expression; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.olingo.odata2.api.edm.EdmComplexType; |
| import org.apache.olingo.odata2.api.edm.EdmEntityType; |
| import org.apache.olingo.odata2.api.edm.EdmException; |
| import org.apache.olingo.odata2.api.edm.EdmMultiplicity; |
| import org.apache.olingo.odata2.api.edm.EdmSimpleType; |
| import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind; |
| import org.apache.olingo.odata2.api.edm.EdmStructuralType; |
| import org.apache.olingo.odata2.api.edm.EdmType; |
| import org.apache.olingo.odata2.api.edm.EdmTypeKind; |
| import org.apache.olingo.odata2.api.edm.EdmTyped; |
| import org.apache.olingo.odata2.api.uri.expression.BinaryExpression; |
| import org.apache.olingo.odata2.api.uri.expression.BinaryOperator; |
| import org.apache.olingo.odata2.api.uri.expression.CommonExpression; |
| import org.apache.olingo.odata2.api.uri.expression.ExpressionKind; |
| import org.apache.olingo.odata2.api.uri.expression.ExpressionParserException; |
| import org.apache.olingo.odata2.api.uri.expression.FilterExpression; |
| import org.apache.olingo.odata2.api.uri.expression.LiteralExpression; |
| import org.apache.olingo.odata2.api.uri.expression.MethodExpression; |
| import org.apache.olingo.odata2.api.uri.expression.MethodOperator; |
| import org.apache.olingo.odata2.api.uri.expression.UnaryExpression; |
| import org.apache.olingo.odata2.api.uri.expression.UnaryOperator; |
| import org.apache.olingo.odata2.core.edm.EdmBoolean; |
| import org.apache.olingo.odata2.core.edm.EdmSimpleTypeFacadeImpl; |
| |
| /** |
| * |
| */ |
| public class FilterParserImpl implements FilterParser { |
| /* do the static initialization */ |
| protected static Map<String, InfoBinaryOperator> availableBinaryOperators; |
| protected static Map<String, InfoMethod> availableMethods; |
| protected static Map<String, InfoUnaryOperator> availableUnaryOperators; |
| |
| static { |
| initAvailTables(); |
| } |
| |
| /* instance attributes */ |
| protected EdmEntityType resourceEntityType = null; |
| protected TokenList tokenList = null; |
| protected String curExpression; |
| protected String originalFilterString = ""; |
| protected String decodedFilterString = ""; |
| private boolean strictFilter = true; |
| |
| |
| /** |
| * Creates a new FilterParser implementation |
| * @param resourceEntityType EntityType of the resource on which the filter is applied |
| */ |
| public FilterParserImpl(final EdmEntityType resourceEntityType) { |
| this.resourceEntityType = resourceEntityType; |
| } |
| |
| /** |
| * Creates a new FilterParser implementation |
| * @param resourceEntityType EntityType of the resource on which the filter is applied |
| * @param strictFilter boolean check to decide weather to validate filter |
| */ |
| public FilterParserImpl(final EdmEntityType resourceEntityType, boolean strictFilter) { |
| this.resourceEntityType = resourceEntityType; |
| this.strictFilter = strictFilter; |
| } |
| |
| /** |
| * Creates a new FilterParser implementation |
| * @param resourceEntityType EntityType of the resource on which the filter is applied |
| * @param strictFilter boolean check to decide weather to validate filter |
| * @param originalFilterString String original filter string prior to decoding |
| */ |
| public FilterParserImpl(final EdmEntityType resourceEntityType, boolean strictFilter, |
| String originalFilterString) { |
| this.resourceEntityType = resourceEntityType; |
| this.strictFilter = strictFilter; |
| this.originalFilterString = originalFilterString; |
| } |
| |
| @Override |
| public FilterExpression parseFilterString(final String filterExpression) throws ExpressionParserException, |
| ExpressionParserInternalError { |
| return parseFilterString(filterExpression, false); |
| } |
| |
| public FilterExpression parseFilterString(final String filterExpression, final boolean allowOnlyBinary) |
| throws ExpressionParserException, ExpressionParserInternalError { |
| CommonExpression node = null; |
| curExpression = filterExpression; |
| decodedFilterString = filterExpression; |
| try { |
| // Throws TokenizerException and FilterParserException. FilterParserException is caught somewhere above |
| tokenList = new Tokenizer(filterExpression).tokenize(); |
| if (!tokenList.hasTokens()) { |
| return new FilterExpressionImpl(filterExpression); |
| } |
| } catch (TokenizerException tokenizerException) { |
| // Tested with TestParserExceptions.TestPMparseFilterString |
| throw FilterParserExceptionImpl.createERROR_IN_TOKENIZER(tokenizerException, curExpression); |
| } |
| |
| try { |
| CommonExpression nodeLeft = readElement(null); |
| node = readElements(nodeLeft, 0); |
| } catch (ExpressionParserException filterParserException) { |
| // Add empty filterTree to Exception |
| // Tested for original throw point |
| filterParserException.setFilterTree(new FilterExpressionImpl(filterExpression)); |
| throw filterParserException; |
| } |
| |
| // Post check |
| if (tokenList.tokenCount() > tokenList.currentToken) // this indicates that not all tokens have been read |
| { |
| // Tested with TestParserExceptions.TestPMparseFilterString |
| throw FilterParserExceptionImpl.createINVALID_TRAILING_TOKEN_DETECTED_AFTER_PARSING(tokenList |
| .elementAt(tokenList.currentToken), filterExpression); |
| } |
| |
| // Create and return filterExpression node |
| if ((allowOnlyBinary == true) && (node.getEdmType() != null) |
| && (node.getEdmType() != EdmSimpleTypeKind.Boolean.getEdmSimpleTypeInstance())) { |
| // Tested with TestParserExceptions.testAdditionalStuff CASE 9 |
| throw FilterParserExceptionImpl.createTYPE_EXPECTED_AT(EdmBoolean.getInstance(), node.getEdmType(), 1, |
| curExpression); |
| } |
| if (filterExpression.equals(decodedFilterString)) { |
| return new FilterExpressionImpl(filterExpression, node); |
| } else { |
| return new FilterExpressionImpl(decodedFilterString, node); |
| } |
| } |
| |
| protected CommonExpression readElements(final CommonExpression leftExpression, final int priority) |
| throws ExpressionParserException, ExpressionParserInternalError { |
| CommonExpression leftNode = leftExpression; |
| CommonExpression rightNode; |
| BinaryExpression binaryNode; |
| |
| ActualBinaryOperator operator = readBinaryOperator(); |
| ActualBinaryOperator nextOperator; |
| |
| while ((operator != null) && (operator.getOP().getPriority() >= priority)) { |
| tokenList.next(); // eat the operator |
| rightNode = readElement(leftNode, operator); // throws FilterParserException, FilterParserInternalError |
| if (rightNode == null) { |
| // Tested with TestParserExceptions.testAdditionalStuff CASE 10 |
| throw FilterParserExceptionImpl.createEXPRESSION_EXPECTED_AFTER_POS(operator.getToken().getPosition() |
| + operator.getToken().getUriLiteral().length(), curExpression); |
| } |
| nextOperator = readBinaryOperator(); |
| |
| // It must be "while" because for example in "Filter=a or c eq d and e eq f" |
| // after reading the "eq" operator the "and" operator must be consumed too. This is due to the fact that "and" has |
| // a higher priority than "or" |
| while ((nextOperator != null) && (nextOperator.getOP().getPriority() > operator.getOP().getPriority())) { |
| // recurse until the a binary operator with a lower priority is detected |
| rightNode = readElements(rightNode, nextOperator.getOP().getPriority()); |
| nextOperator = readBinaryOperator(); |
| } |
| |
| // Although the member operator is also a binary operator, there is some special handling in the filterTree |
| if (operator.getOP().getOperator() == BinaryOperator.PROPERTY_ACCESS) { |
| binaryNode = new MemberExpressionImpl(leftNode, rightNode); |
| } else { |
| binaryNode = new BinaryExpressionImpl(operator.getOP(), leftNode, rightNode, operator.getToken()); |
| } |
| |
| try { |
| validateBinaryOperatorTypes(binaryNode); |
| } catch (ExpressionParserException expressionException) { |
| // Extend the error information |
| // Tested for original throw point |
| expressionException.setFilterTree(binaryNode); |
| throw expressionException; |
| } |
| |
| leftNode = binaryNode; |
| operator = readBinaryOperator(); |
| } |
| |
| // Add special handling for expressions like $filter=notsupportedfunction('a') |
| // If this special handling is not in place the error text would be |
| // -->Invalid token "(" detected after parsing at position 21 in "notsupportedfunction('a')". |
| // with this special handling we ensure that the error text would be |
| |
| Token token = tokenList.lookToken(); |
| if (token != null) { |
| if ((leftNode.getKind() == ExpressionKind.PROPERTY) && (tokenList.lookToken().getKind() == TokenKind.OPENPAREN)) { |
| // Tested with TestParserExceptions.testAdditionalStuff CASE 2 |
| throw FilterParserExceptionImpl.createINVALID_METHOD_CALL(leftNode, tokenList.lookPrevToken(), curExpression); |
| } |
| } |
| |
| return leftNode; |
| } |
| |
| /** |
| * Reads the content between parenthesis. Its is expected that the current token is of kind |
| * {@link TokenKind#OPENPAREN} because it MUST be check in the calling method ( when read the method name and the '(' |
| * is read). |
| * @return An expression which reflects the content within the parenthesis |
| * @throws ExpressionParserException |
| * While reading the elements in the parenthesis an error occurred |
| * @throws TokenizerMessage |
| * The next token did not match the expected token |
| */ |
| protected CommonExpression readParenthesis() throws ExpressionParserException, ExpressionParserInternalError { |
| // The existing of a '(' is verified BEFORE this method is called --> so it's a internal error |
| Token openParenthesis = tokenList.expectToken(TokenKind.OPENPAREN, true); |
| |
| CommonExpression firstExpression = readElement(null); |
| CommonExpression parenthesisExpression = readElements(firstExpression, 0); |
| |
| // check for ')' |
| try { |
| tokenList.expectToken(TokenKind.CLOSEPAREN); // TokenizerMessage |
| } catch (TokenizerExpectError e) { |
| // Internal parsing error, even if there are no more token (then there should be a different exception). |
| // Tested with TestParserExceptions.TestPMreadParenthesis |
| throw FilterParserExceptionImpl.createMISSING_CLOSING_PARENTHESIS(openParenthesis.getPosition(), curExpression, |
| e); |
| } |
| return parenthesisExpression; |
| } |
| |
| /** |
| * Read the parameters of a method expression |
| * @param methodInfo |
| * Signature information about the method whose parameters should be read |
| * @param methodExpression |
| * Method expression to which the read parameters are added |
| * @return |
| * The method expression input parameter |
| * @throws ExpressionParserException |
| * @throws ExpressionParserInternalError |
| * @throws TokenizerExpectError |
| * The next token did not match the expected token |
| */ |
| protected MethodExpression readParameters(final InfoMethod methodInfo, final MethodExpressionImpl methodExpression, |
| final Token methodToken) throws ExpressionParserException, ExpressionParserInternalError { |
| CommonExpression expression; |
| boolean expectAnotherExpression = false; |
| boolean readComma = true; |
| |
| // The existing of a '(' is verified BEFORE this method is called --> so it's a internal error |
| Token openParenthesis = tokenList.expectToken(TokenKind.OPENPAREN, true); // throws FilterParserInternalError |
| |
| Token token = tokenList.lookToken(); |
| if (token == null) { |
| // Tested with TestParserExceptions.TestPMreadParameters CASE 1 e.g. "$filter=concat(" |
| throw FilterParserExceptionImpl.createEXPRESSION_EXPECTED_AFTER_POS(openParenthesis, curExpression); |
| } |
| |
| while (token.getKind() != TokenKind.CLOSEPAREN) { |
| if (readComma == false) { |
| // Tested with TestParserExceptions.TestPMreadParameters CASE 12 e.g. "$filter=concat('a' 'b')" |
| throw FilterParserExceptionImpl.createCOMMA_OR_CLOSING_PARENTHESIS_EXPECTED_AFTER_POS(tokenList |
| .lookPrevToken(), curExpression); |
| } |
| expression = readElement(null); |
| if (expression != null) { |
| expression = readElements(expression, 0); |
| } |
| |
| if ((expression == null) && (expectAnotherExpression == true)) { |
| // Tested with TestParserExceptions.TestPMreadParameters CASE 4 e.g. "$filter=concat(," |
| throw FilterParserExceptionImpl.createEXPRESSION_EXPECTED_AFTER_POS(token, curExpression); |
| } else if (expression != null) {// parameter list may be empty |
| methodExpression.appendParameter(expression); |
| } |
| |
| token = tokenList.lookToken(); |
| if (token == null) { |
| // Tested with TestParserExceptions.TestPMreadParameters CASE 2 e.g. "$filter=concat(123" |
| throw FilterParserExceptionImpl.createCOMMA_OR_CLOSING_PARENTHESIS_EXPECTED_AFTER_POS(tokenList |
| .lookPrevToken(), curExpression); |
| } |
| |
| if (token.getKind() == TokenKind.COMMA) { |
| expectAnotherExpression = true; |
| if (expression == null) { |
| // Tested with TestParserExceptions.TestPMreadParameters CASE 3 e.g. "$filter=concat(," |
| throw FilterParserExceptionImpl.createEXPRESSION_EXPECTED_AT_POS(token, curExpression); |
| } |
| |
| tokenList.expectToken(",", true); |
| readComma = true; |
| } else { |
| readComma = false; |
| } |
| } |
| |
| // because the while loop above only exits if a ')' has been found it is an |
| // internal error if there is not ')' |
| tokenList.expectToken(TokenKind.CLOSEPAREN, true); |
| |
| // ---check parameter count |
| int count = methodExpression.getParameters().size(); |
| if ((methodInfo.getMinParameter() > -1) && (count < methodInfo.getMinParameter())) { |
| // Tested with TestParserExceptions.TestPMreadParameters CASE 12 |
| throw FilterParserExceptionImpl.createMETHOD_WRONG_ARG_COUNT(methodExpression, methodToken, curExpression); |
| } |
| |
| if ((methodInfo.getMaxParameter() > -1) && (count > methodInfo.getMaxParameter())) { |
| // Tested with TestParserExceptions.TestPMreadParameters CASE 15 |
| throw FilterParserExceptionImpl.createMETHOD_WRONG_ARG_COUNT(methodExpression, methodToken, curExpression); |
| } |
| |
| return methodExpression; |
| } |
| |
| protected CommonExpression readElement(final CommonExpression leftExpression) throws ExpressionParserException, |
| ExpressionParserInternalError { |
| return readElement(leftExpression, null); |
| } |
| |
| /** |
| * Reads: Unary operators, Methods, Properties, ... |
| * but not binary operators which are handelt in {@link #readElements(CommonExpression, int)} |
| * @param leftExpression |
| * Used while parsing properties. In this case ( e.g. parsing "a/b") the property "a" ( as leftExpression of "/") is |
| * relevant |
| * to verify whether the property "b" exists inside the edm |
| * @return a CommonExpression |
| * @throws ExpressionParserException |
| * @throws ExpressionParserInternalError |
| * @throws TokenizerMessage |
| */ |
| protected CommonExpression |
| readElement(final CommonExpression leftExpression, final ActualBinaryOperator leftOperator) |
| throws ExpressionParserException, ExpressionParserInternalError { |
| CommonExpression node = null; |
| Token token; |
| Token lookToken; |
| lookToken = tokenList.lookToken(); |
| if (lookToken == null) { |
| return null; |
| } |
| |
| switch (lookToken.getKind()) { |
| case OPENPAREN: |
| node = readParenthesis(); |
| return node; |
| case CLOSEPAREN: // ')' finishes a parenthesis (it is no extra token)" + |
| case COMMA: // . " ',' is a separator for function parameters (it is no extra token)" + |
| return null; |
| default: |
| // continue |
| } |
| |
| // -->Check if the token is a unary operator |
| InfoUnaryOperator unaryOperator = isUnaryOperator(lookToken); |
| if (unaryOperator != null) { |
| return readUnaryoperator(lookToken, unaryOperator); |
| } |
| |
| // ---expect the look ahead token |
| token = tokenList.expectToken(lookToken.getUriLiteral(), true); |
| lookToken = tokenList.lookToken(); |
| |
| // -->Check if the token is a method |
| // To avoid name clashes between method names and property names we accept here only method names if a "(" follows. |
| // Hence the parser accepts a property named "concat" |
| InfoMethod methodOperator = isMethod(token, lookToken); |
| if (methodOperator != null) { |
| return readMethod(token, methodOperator); |
| } |
| |
| // -->Check if token is a terminal |
| // is a terminal e.g. a Value like an EDM.String 'hugo' or 125L or 1.25D" |
| if (token.getKind() == TokenKind.SIMPLE_TYPE) { |
| LiteralExpression literal = new LiteralExpressionImpl( |
| getEncodedUriLiteral(token.getUriLiteral(),token.getPosition()), token.getJavaLiteral()); |
| return literal; |
| } |
| |
| // -->Check if token is a property, e.g. "name" or "address" |
| if (token.getKind() == TokenKind.LITERAL) { |
| PropertyExpressionImpl property = new PropertyExpressionImpl(token.getUriLiteral(), token.getJavaLiteral()); |
| validateEdmProperty(leftExpression, property, token, leftOperator); |
| return property; |
| } |
| |
| // not Tested, should not occur |
| throw ExpressionParserInternalError.createCOMMON(); |
| } |
| |
| protected CommonExpression readUnaryoperator(final Token lookToken, final InfoUnaryOperator unaryOperator) |
| throws ExpressionParserException, ExpressionParserInternalError { |
| tokenList.expectToken(lookToken.getUriLiteral(), true); |
| |
| CommonExpression operand = readElement(null); |
| UnaryExpression unaryExpression = new UnaryExpressionImpl(unaryOperator, operand); |
| validateUnaryOperatorTypes(unaryExpression); // throws ExpressionInvalidOperatorTypeException |
| |
| return unaryExpression; |
| } |
| |
| protected CommonExpression readMethod(final Token token, final InfoMethod methodOperator) |
| throws ExpressionParserException, ExpressionParserInternalError { |
| MethodExpressionImpl method = new MethodExpressionImpl(methodOperator); |
| |
| readParameters(methodOperator, method, token); |
| validateMethodTypes(method, token); // throws ExpressionInvalidOperatorTypeException |
| |
| return method; |
| } |
| |
| protected ActualBinaryOperator readBinaryOperator() { |
| InfoBinaryOperator operator = null; |
| Token token = tokenList.lookToken(); |
| if (token == null) { |
| return null; |
| } |
| if ((token.getKind() == TokenKind.SYMBOL) && ("/".equals(token.getUriLiteral()))) { |
| operator = availableBinaryOperators.get(token.getUriLiteral()); |
| } else if (token.getKind() == TokenKind.LITERAL) { |
| operator = availableBinaryOperators.get(token.getUriLiteral()); |
| } |
| |
| if (operator == null) { |
| return null; |
| } |
| |
| return new ActualBinaryOperator(operator, token); |
| } |
| |
| /** |
| * Check if a token is a UnaryOperator ( e.g. "not" or "-" ) |
| * |
| * @param token Token to be checked |
| * |
| * @return |
| * <li>An instance of {@link InfoUnaryOperator} containing information about the specific unary operator</li> |
| * <li><code>null</code> if the token is not an unary operator</li> |
| */ |
| protected InfoUnaryOperator isUnaryOperator(final Token token) { |
| if ((token.getKind() == TokenKind.LITERAL) || (token.getKind() == TokenKind.SYMBOL)) { |
| InfoUnaryOperator operator = availableUnaryOperators.get(token.getUriLiteral()); |
| return operator; |
| } |
| return null; |
| } |
| |
| protected InfoMethod isMethod(final Token token, final Token lookToken) { |
| if ((lookToken != null) && (lookToken.getKind() == TokenKind.OPENPAREN)) { |
| return availableMethods.get(token.getUriLiteral()); |
| } |
| return null; |
| } |
| |
| protected void validateEdmProperty(final CommonExpression leftExpression, final PropertyExpressionImpl property, |
| final Token propertyToken, final ActualBinaryOperator actBinOp) throws ExpressionParserException, |
| ExpressionParserInternalError { |
| |
| // Exit if no edm provided |
| if (resourceEntityType == null) { |
| return; |
| } |
| |
| if (leftExpression == null) { |
| // e.g. "$filter=city eq 'Hong Kong'" --> "city" is checked against the resource entity type of the last URL |
| // segment |
| validateEdmPropertyOfStructuredType(resourceEntityType, property, propertyToken); |
| return; |
| } |
| // e.g. "$filter='Hong Kong' eq address/city" --> city is "checked" against the type of the property "address". |
| // "address" itself must be a (navigation)property of the resource entity type of the last URL segment AND |
| // "address" must have a structural edm type |
| EdmType parentType = leftExpression.getEdmType(); // parentType point now to the type of property "address" |
| |
| if ((actBinOp != null) && (actBinOp.operator.getOperator() != BinaryOperator.PROPERTY_ACCESS)) { |
| validateEdmPropertyOfStructuredType(resourceEntityType, property, propertyToken); |
| return; |
| } else { |
| if ((leftExpression.getKind() != ExpressionKind.PROPERTY) && |
| (leftExpression.getKind() != ExpressionKind.MEMBER)) { |
| if (actBinOp != null) { |
| // Tested with TestParserExceptions.TestPMvalidateEdmProperty CASE 6 |
| throw FilterParserExceptionImpl.createLEFT_SIDE_NOT_A_PROPERTY(actBinOp.token, curExpression); |
| } else { |
| // not Tested, should not occur |
| throw ExpressionParserInternalError.createCOMMON(); |
| } |
| |
| } |
| } |
| |
| if (parentType instanceof EdmEntityType) { |
| // e.g. "$filter='Hong Kong' eq navigationProp/city" --> "navigationProp" is a navigation property with a entity |
| // type |
| validateEdmPropertyOfStructuredType((EdmStructuralType) parentType, property, propertyToken); |
| } else if (parentType instanceof EdmComplexType) { |
| // e.g. "$filter='Hong Kong' eq address/city" --> "address" is a property with a complex type |
| validateEdmPropertyOfStructuredType((EdmStructuralType) parentType, property, propertyToken); |
| } else { |
| // e.g. "$filter='Hong Kong' eq name/city" --> "name is of type String" |
| // Tested with TestParserExceptions.TestPMvalidateEdmProperty CASE 5 |
| throw FilterParserExceptionImpl.createLEFT_SIDE_NOT_STRUCTURAL_TYPE(parentType, property, propertyToken, |
| curExpression); |
| } |
| |
| return; |
| } |
| |
| protected void validateEdmPropertyOfStructuredType(final EdmStructuralType parentType, |
| final PropertyExpressionImpl property, final Token propertyToken) throws ExpressionParserException, |
| ExpressionParserInternalError { |
| try { |
| String propertyName = property.getUriLiteral(); |
| EdmTyped edmProperty = parentType.getProperty(propertyName); |
| |
| if (edmProperty != null) { |
| property.setEdmProperty(edmProperty); |
| property.setEdmType(edmProperty.getType()); |
| if(isLastFilterElement(propertyName)) { |
| if (edmProperty.getMultiplicity() == EdmMultiplicity.MANY && strictFilter) { |
| throw new ExpressionParserException( |
| ExpressionParserException.INVALID_MULTIPLICITY.create() |
| .addContent(propertyName) |
| .addContent(propertyToken.getPosition() + 1)); |
| } |
| } |
| } else { |
| // Tested with TestParserExceptions.TestPMvalidateEdmProperty CASE 3 |
| throw FilterParserExceptionImpl.createPROPERTY_NAME_NOT_FOUND_IN_TYPE(parentType, property, propertyToken, |
| curExpression); |
| } |
| |
| } catch (EdmException e) { |
| // not Tested, should not occur |
| throw ExpressionParserInternalError.createERROR_ACCESSING_EDM(e); |
| } |
| } |
| |
| /** |
| * Check if the property name is the last or only element of the filter |
| * @param propertyName name of the property |
| * @return <code>true</code> if this is the last or only otherwise <code>false</code> |
| */ |
| private boolean isLastFilterElement(String propertyName) { |
| return curExpression.contains(propertyName + " "); |
| } |
| |
| protected void validateUnaryOperatorTypes(final UnaryExpression unaryExpression) |
| throws ExpressionParserInternalError { |
| InfoUnaryOperator unOpt = availableUnaryOperators.get(unaryExpression.getOperator().toUriLiteral()); |
| EdmType operandType = unaryExpression.getOperand().getEdmType(); |
| |
| if ((operandType == null) && (resourceEntityType == null)) { |
| return; |
| } |
| |
| List<EdmType> actualParameterTypes = new ArrayList<EdmType>(); |
| actualParameterTypes.add(operandType); |
| |
| ParameterSet parameterSet = unOpt.validateParameterSet(actualParameterTypes); |
| if (parameterSet != null) { |
| unaryExpression.setEdmType(parameterSet.getReturnType()); |
| } |
| } |
| |
| protected void validateBinaryOperatorTypes(final BinaryExpression binaryExpression) throws ExpressionParserException, |
| ExpressionParserInternalError { |
| InfoBinaryOperator binOpt = availableBinaryOperators.get(binaryExpression.getOperator().toUriLiteral()); |
| |
| List<EdmType> actualParameterTypes = new ArrayList<EdmType>(); |
| final EdmType leftType = binaryExpression.getLeftOperand().getEdmType(); |
| if (leftType == null && resourceEntityType == null) { |
| return; |
| } |
| actualParameterTypes.add(leftType); |
| |
| final EdmType rightType = binaryExpression.getRightOperand().getEdmType(); |
| if (rightType == null && resourceEntityType == null) { |
| return; |
| } |
| actualParameterTypes.add(rightType); |
| |
| // special case for navigation property (non-)equality comparison with null |
| if ("Equality".equals(binOpt.getCategory()) |
| && (leftType != null && leftType.getKind() == EdmTypeKind.ENTITY |
| && rightType == EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Null) |
| || leftType == EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Null) |
| && rightType != null && rightType.getKind() == EdmTypeKind.ENTITY)) { |
| binaryExpression.setEdmType(EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Boolean)); |
| return; |
| } |
| |
| final ParameterSet parameterSet = binOpt.validateParameterSet(actualParameterTypes); |
| if (parameterSet == null) { |
| BinaryExpressionImpl binaryExpressionImpl = (BinaryExpressionImpl) binaryExpression; |
| |
| // Tested with TestParserExceptions.TestPMvalidateBinaryOperator |
| throw FilterParserExceptionImpl.createINVALID_TYPES_FOR_BINARY_OPERATOR(binaryExpression.getOperator(), |
| binaryExpression.getLeftOperand().getEdmType(), binaryExpression.getRightOperand().getEdmType(), |
| binaryExpressionImpl.getToken(), curExpression); |
| } |
| binaryExpression.setEdmType(parameterSet.getReturnType()); |
| } |
| |
| protected void validateMethodTypes(final MethodExpression methodExpression, final Token methodToken) |
| throws ExpressionParserException, ExpressionParserInternalError { |
| InfoMethod methOpt = availableMethods.get(methodExpression.getUriLiteral()); |
| |
| List<EdmType> actualParameterTypes = new ArrayList<EdmType>(); |
| |
| // If there are no parameter then don't perform a type check |
| if (methodExpression.getParameters().isEmpty()) { |
| return; |
| } |
| |
| for (CommonExpression parameter : methodExpression.getParameters()) { |
| // If there is not at parsing time its not possible to determine the type of eg myPropertyName. |
| // Since this should not cause validation errors null type node arguments are leading to bypass |
| // the validation |
| if (parameter.getEdmType() == null && resourceEntityType == null) { |
| return; |
| } |
| actualParameterTypes.add(parameter.getEdmType()); |
| } |
| |
| ParameterSet parameterSet = methOpt.validateParameterSet(actualParameterTypes); |
| // If there is not returntype then the input parameter |
| if (parameterSet == null) { |
| // Tested with TestParserExceptions.testPMvalidateMethodTypes CASE 1 |
| throw FilterParserExceptionImpl.createMETHOD_WRONG_INPUT_TYPE((MethodExpressionImpl) methodExpression, |
| methodToken, curExpression); |
| } |
| methodExpression.setEdmType(parameterSet.getReturnType()); |
| } |
| |
| /* |
| * In case we have + in the string literal and is replaced with ' '(space) in UriParserImpl |
| * it needs to be changed back to + |
| */ |
| private String getEncodedUriLiteral(String uriLiteral,int pos) { |
| if (originalFilterString.length()!=0 && uriLiteral.contains(" ")) { |
| String encodedUriLiteral = uriLiteral.replaceAll(" ", "+"); |
| String originalFilterToken = originalFilterString.substring(pos,pos+uriLiteral.length()); |
| if (originalFilterToken!=null && originalFilterToken.equals(encodedUriLiteral)) { |
| decodedFilterString=decodedFilterString.substring(0, pos)+encodedUriLiteral+ |
| decodedFilterString.substring(pos+uriLiteral.length()); |
| uriLiteral = encodedUriLiteral; |
| } |
| } |
| return uriLiteral; |
| } |
| |
| static void initAvailTables() { |
| Map<String, InfoBinaryOperator> lAvailableBinaryOperators = new HashMap<String, InfoBinaryOperator>(); |
| Map<String, InfoMethod> lAvailableMethods = new HashMap<String, InfoMethod>(); |
| Map<String, InfoUnaryOperator> lAvailableUnaryOperators = new HashMap<String, InfoUnaryOperator>(); |
| |
| // create type validators |
| ParameterSetCombination combination = null; |
| // create type helpers |
| EdmSimpleType boolean_ = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Boolean); |
| EdmSimpleType sbyte = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.SByte); |
| EdmSimpleType byte_ = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Byte); |
| EdmSimpleType int16 = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Int16); |
| EdmSimpleType int32 = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Int32); |
| EdmSimpleType int64 = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Int64); |
| EdmSimpleType single = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Single); |
| EdmSimpleType double_ = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Double); |
| EdmSimpleType decimal = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Decimal); |
| EdmSimpleType string = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.String); |
| EdmSimpleType time = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Time); |
| EdmSimpleType datetime = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.DateTime); |
| EdmSimpleType datetimeoffset = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.DateTimeOffset); |
| EdmSimpleType guid = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Guid); |
| EdmSimpleType binary = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Binary); |
| EdmSimpleType null_ = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Null); |
| |
| // ---Member member access--- |
| lAvailableBinaryOperators.put("/", new InfoBinaryOperator(BinaryOperator.PROPERTY_ACCESS, "Primary", 100, |
| new ParameterSetCombination.PSCReturnTypeEqLastParameter()));// todo fix this |
| |
| // ---Multiplicative--- |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(sbyte, sbyte, sbyte)); |
| combination.add(new ParameterSet(byte_, byte_, byte_)); |
| combination.add(new ParameterSet(int16, int16, int16)); |
| combination.add(new ParameterSet(int32, int32, int32)); |
| combination.add(new ParameterSet(int64, int64, int64)); |
| combination.add(new ParameterSet(single, single, single)); |
| combination.add(new ParameterSet(double_, double_, double_)); |
| combination.add(new ParameterSet(decimal, decimal, decimal)); |
| |
| combination.add(new ParameterSet(sbyte, sbyte, null_)); |
| combination.add(new ParameterSet(sbyte, null_, sbyte)); |
| combination.add(new ParameterSet(byte_, byte_, null_)); |
| combination.add(new ParameterSet(byte_, null_, byte_)); |
| |
| combination.add(new ParameterSet(int16, int16, null_)); |
| combination.add(new ParameterSet(int16, null_, int16)); |
| combination.add(new ParameterSet(int32, int32, null_)); |
| combination.add(new ParameterSet(int32, null_, int32)); |
| combination.add(new ParameterSet(int64, int64, null_)); |
| combination.add(new ParameterSet(int64, null_, int64)); |
| |
| combination.add(new ParameterSet(single, single, null_)); |
| combination.add(new ParameterSet(single, null_, single)); |
| combination.add(new ParameterSet(double_, double_, null_)); |
| combination.add(new ParameterSet(double_, null_, double_)); |
| combination.add(new ParameterSet(decimal, decimal, null_)); |
| combination.add(new ParameterSet(decimal, null_, decimal)); |
| |
| lAvailableBinaryOperators.put(BinaryOperator.MUL.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.MUL, |
| "Multiplicative", 60, combination)); |
| lAvailableBinaryOperators.put(BinaryOperator.DIV.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.DIV, |
| "Multiplicative", 60, combination)); |
| lAvailableBinaryOperators.put(BinaryOperator.MODULO.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.MODULO, |
| "Multiplicative", 60, combination)); |
| |
| // ---Additive--- |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(sbyte, sbyte, sbyte)); |
| combination.add(new ParameterSet(byte_, byte_, byte_)); |
| combination.add(new ParameterSet(int16, int16, int16)); |
| combination.add(new ParameterSet(int32, int32, int32)); |
| combination.add(new ParameterSet(int64, int64, int64)); |
| combination.add(new ParameterSet(single, single, single)); |
| combination.add(new ParameterSet(double_, double_, double_)); |
| combination.add(new ParameterSet(decimal, decimal, decimal)); |
| |
| combination.add(new ParameterSet(sbyte, sbyte, null_)); |
| combination.add(new ParameterSet(sbyte, null_, sbyte)); |
| combination.add(new ParameterSet(byte_, byte_, null_)); |
| combination.add(new ParameterSet(byte_, null_, byte_)); |
| |
| combination.add(new ParameterSet(int16, int16, null_)); |
| combination.add(new ParameterSet(int16, null_, int16)); |
| combination.add(new ParameterSet(int32, int32, null_)); |
| combination.add(new ParameterSet(int32, null_, int32)); |
| combination.add(new ParameterSet(int64, int64, null_)); |
| combination.add(new ParameterSet(int64, null_, int64)); |
| |
| combination.add(new ParameterSet(single, single, null_)); |
| combination.add(new ParameterSet(single, null_, single)); |
| combination.add(new ParameterSet(double_, double_, null_)); |
| combination.add(new ParameterSet(double_, null_, double_)); |
| combination.add(new ParameterSet(decimal, decimal, null_)); |
| combination.add(new ParameterSet(decimal, null_, decimal)); |
| |
| lAvailableBinaryOperators.put(BinaryOperator.ADD.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.ADD, |
| "Additive", 50, combination)); |
| lAvailableBinaryOperators.put(BinaryOperator.SUB.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.SUB, |
| "Additive", 50, combination)); |
| |
| // ---Relational--- |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(boolean_, string, string)); |
| combination.add(new ParameterSet(boolean_, time, time)); |
| combination.add(new ParameterSet(boolean_, datetime, datetime)); |
| combination.add(new ParameterSet(boolean_, datetimeoffset, datetimeoffset)); |
| combination.add(new ParameterSet(boolean_, guid, guid)); |
| combination.add(new ParameterSet(boolean_, sbyte, sbyte)); |
| combination.add(new ParameterSet(boolean_, byte_, byte_)); |
| combination.add(new ParameterSet(boolean_, int16, int16)); |
| combination.add(new ParameterSet(boolean_, int32, int32)); |
| combination.add(new ParameterSet(boolean_, int64, int64)); |
| combination.add(new ParameterSet(boolean_, single, single)); |
| combination.add(new ParameterSet(boolean_, double_, double_)); |
| combination.add(new ParameterSet(boolean_, decimal, decimal)); |
| combination.add(new ParameterSet(boolean_, binary, binary)); |
| |
| combination.add(new ParameterSet(boolean_, string, null_)); |
| combination.add(new ParameterSet(boolean_, null_, string)); |
| |
| combination.add(new ParameterSet(boolean_, time, null_)); |
| combination.add(new ParameterSet(boolean_, null_, time)); |
| |
| combination.add(new ParameterSet(boolean_, datetime, null_)); |
| combination.add(new ParameterSet(boolean_, null_, datetime)); |
| |
| combination.add(new ParameterSet(boolean_, datetimeoffset, null_)); |
| combination.add(new ParameterSet(boolean_, null_, datetimeoffset)); |
| |
| combination.add(new ParameterSet(boolean_, guid, null_)); |
| combination.add(new ParameterSet(boolean_, null_, guid)); |
| |
| combination.add(new ParameterSet(boolean_, sbyte, null_)); |
| combination.add(new ParameterSet(boolean_, null_, sbyte)); |
| combination.add(new ParameterSet(boolean_, byte_, null_)); |
| combination.add(new ParameterSet(boolean_, null_, byte_)); |
| |
| combination.add(new ParameterSet(boolean_, int16, null_)); |
| combination.add(new ParameterSet(boolean_, null_, int16)); |
| combination.add(new ParameterSet(boolean_, int32, null_)); |
| combination.add(new ParameterSet(boolean_, null_, int32)); |
| combination.add(new ParameterSet(boolean_, int64, null_)); |
| combination.add(new ParameterSet(boolean_, null_, int64)); |
| |
| combination.add(new ParameterSet(boolean_, single, null_)); |
| combination.add(new ParameterSet(boolean_, null_, single)); |
| combination.add(new ParameterSet(boolean_, double_, null_)); |
| combination.add(new ParameterSet(boolean_, null_, double_)); |
| combination.add(new ParameterSet(boolean_, decimal, null_)); |
| combination.add(new ParameterSet(boolean_, null_, decimal)); |
| |
| combination.add(new ParameterSet(boolean_, binary, null_)); |
| combination.add(new ParameterSet(boolean_, null_, binary)); |
| |
| |
| lAvailableBinaryOperators.put(BinaryOperator.LT.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.LT, |
| "Relational", 40, combination)); |
| lAvailableBinaryOperators.put(BinaryOperator.GT.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.GT, |
| "Relational", 40, combination)); |
| lAvailableBinaryOperators.put(BinaryOperator.GE.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.GE, |
| "Relational", 40, combination)); |
| lAvailableBinaryOperators.put(BinaryOperator.LE.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.LE, |
| "Relational", 40, combination)); |
| |
| // ---Equality--- |
| combination.addFirst(new ParameterSet(boolean_, boolean_, boolean_)); |
| |
| combination.add(new ParameterSet(boolean_, boolean_, null_)); |
| combination.add(new ParameterSet(boolean_, null_, boolean_)); |
| |
| lAvailableBinaryOperators.put(BinaryOperator.EQ.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.EQ, |
| "Equality", 30, combination)); |
| lAvailableBinaryOperators.put(BinaryOperator.NE.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.NE, |
| "Equality", 30, combination)); |
| |
| // "---Conditional AND--- |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(boolean_, boolean_, boolean_)); |
| combination.add(new ParameterSet(boolean_, boolean_, null_)); |
| combination.add(new ParameterSet(boolean_, null_, boolean_)); |
| |
| lAvailableBinaryOperators.put(BinaryOperator.AND.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.AND, |
| "Conditional", 20, combination)); |
| |
| // ---Conditional OR--- |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(boolean_, boolean_, boolean_)); |
| combination.add(new ParameterSet(boolean_, boolean_, null_)); |
| combination.add(new ParameterSet(boolean_, null_, boolean_)); |
| |
| lAvailableBinaryOperators.put(BinaryOperator.OR.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.OR, |
| "Conditional", 10, combination)); |
| |
| // endswith |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(boolean_, string, string)); |
| lAvailableMethods.put(MethodOperator.ENDSWITH.toUriLiteral(), new InfoMethod(MethodOperator.ENDSWITH, 2, 2, |
| combination)); |
| |
| // indexof |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(int32, string, string)); |
| lAvailableMethods.put(MethodOperator.INDEXOF.toUriLiteral(), new InfoMethod(MethodOperator.INDEXOF, 2, 2, |
| combination)); |
| |
| // startswith |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(boolean_, string, string)); |
| lAvailableMethods.put(MethodOperator.STARTSWITH.toUriLiteral(), new InfoMethod(MethodOperator.STARTSWITH, 2, 2, |
| combination)); |
| |
| // tolower |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(string, string)); |
| lAvailableMethods.put(MethodOperator.TOLOWER.toUriLiteral(), new InfoMethod(MethodOperator.TOLOWER, combination)); |
| |
| // toupper |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(string, string)); |
| lAvailableMethods.put(MethodOperator.TOUPPER.toUriLiteral(), new InfoMethod(MethodOperator.TOUPPER, combination)); |
| |
| // trim |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(string, string)); |
| lAvailableMethods.put(MethodOperator.TRIM.toUriLiteral(), new InfoMethod(MethodOperator.TRIM, combination)); |
| |
| // substring |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(string, string, int32)); |
| combination.add(new ParameterSet(string, string, int32, int32)); |
| lAvailableMethods.put(MethodOperator.SUBSTRING.toUriLiteral(), new InfoMethod(MethodOperator.SUBSTRING, 1, -1, |
| combination)); |
| |
| // substringof |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(boolean_, string, string)); |
| lAvailableMethods.put(MethodOperator.SUBSTRINGOF.toUriLiteral(), new InfoMethod(MethodOperator.SUBSTRINGOF, 1, -1, |
| combination)); |
| |
| // replace |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(string, string, string, string)); |
| lAvailableMethods.put(MethodOperator.REPLACE.toUriLiteral(), new InfoMethod(MethodOperator.REPLACE, 3, 3, |
| combination)); |
| |
| // concat |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(string, string, string).setFurtherType(string)); |
| lAvailableMethods.put(MethodOperator.CONCAT.toUriLiteral(), new InfoMethod(MethodOperator.CONCAT, 2, -1, |
| combination)); |
| |
| // length |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(int32, string)); |
| lAvailableMethods.put(MethodOperator.LENGTH.toUriLiteral(), new InfoMethod(MethodOperator.LENGTH, combination)); |
| |
| // year |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(int32, datetime)); |
| lAvailableMethods.put(MethodOperator.YEAR.toUriLiteral(), new InfoMethod(MethodOperator.YEAR, combination)); |
| |
| // month |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(int32, datetime)); |
| lAvailableMethods.put(MethodOperator.MONTH.toUriLiteral(), new InfoMethod(MethodOperator.MONTH, combination)); |
| |
| // day |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(int32, datetime)); |
| lAvailableMethods.put(MethodOperator.DAY.toUriLiteral(), new InfoMethod(MethodOperator.DAY, combination)); |
| |
| // hour |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(int32, datetime)); |
| combination.add(new ParameterSet(int32, time)); |
| combination.add(new ParameterSet(int32, datetimeoffset)); |
| lAvailableMethods.put(MethodOperator.HOUR.toUriLiteral(), new InfoMethod(MethodOperator.HOUR, combination)); |
| |
| // minute |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(int32, datetime)); |
| combination.add(new ParameterSet(int32, time)); |
| combination.add(new ParameterSet(int32, datetimeoffset)); |
| lAvailableMethods.put(MethodOperator.MINUTE.toUriLiteral(), new InfoMethod(MethodOperator.MINUTE, combination)); |
| |
| // second |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(int32, datetime)); |
| combination.add(new ParameterSet(int32, time)); |
| combination.add(new ParameterSet(int32, datetimeoffset)); |
| lAvailableMethods.put(MethodOperator.SECOND.toUriLiteral(), new InfoMethod(MethodOperator.SECOND, combination)); |
| |
| // round |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(decimal, decimal)); |
| combination.add(new ParameterSet(double_, double_)); |
| lAvailableMethods.put(MethodOperator.ROUND.toUriLiteral(), new InfoMethod(MethodOperator.ROUND, combination)); |
| |
| // ceiling |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(decimal, decimal)); |
| combination.add(new ParameterSet(double_, double_)); |
| lAvailableMethods.put(MethodOperator.CEILING.toUriLiteral(), new InfoMethod(MethodOperator.CEILING, combination)); |
| |
| // floor |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(decimal, decimal)); |
| combination.add(new ParameterSet(double_, double_)); |
| lAvailableMethods.put(MethodOperator.FLOOR.toUriLiteral(), new InfoMethod(MethodOperator.FLOOR, combination)); |
| |
| // ---unary--- |
| |
| // minus |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(sbyte, sbyte)); |
| combination.add(new ParameterSet(byte_, byte_)); |
| combination.add(new ParameterSet(int16, int16)); |
| combination.add(new ParameterSet(int32, int32)); |
| combination.add(new ParameterSet(int64, int64)); |
| combination.add(new ParameterSet(single, single)); |
| combination.add(new ParameterSet(double_, double_)); |
| combination.add(new ParameterSet(decimal, decimal)); |
| combination.add(new ParameterSet(null_, null_)); |
| |
| |
| // minus |
| lAvailableUnaryOperators.put(UnaryOperator.MINUS.toUriLiteral(), new InfoUnaryOperator(UnaryOperator.MINUS, |
| "minus", combination)); |
| |
| // not |
| combination = new ParameterSetCombination.PSCflex(); |
| combination.add(new ParameterSet(boolean_, boolean_)); |
| combination.add(new ParameterSet(null_, null_)); |
| lAvailableUnaryOperators.put(UnaryOperator.NOT.toUriLiteral(), new InfoUnaryOperator(UnaryOperator.NOT, "not", |
| combination)); |
| |
| availableBinaryOperators = Collections.unmodifiableMap(lAvailableBinaryOperators); |
| availableMethods = Collections.unmodifiableMap(lAvailableMethods); |
| availableUnaryOperators = Collections.unmodifiableMap(lAvailableUnaryOperators); |
| } |
| } |