/**
* personium.io
* Copyright 2014 FUJITSU LIMITED
*
* 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
*
* 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 com.fujitsu.dc.core.model.impl.es.odata;
import java.util.HashMap;
import java.util.Map;
import org.odata4j.edm.EdmProperty;
import org.odata4j.edm.EdmSimpleType;
import org.odata4j.expression.BooleanLiteral;
import org.odata4j.expression.CommonExpression;
import org.odata4j.expression.DoubleLiteral;
import org.odata4j.expression.Int64Literal;
import org.odata4j.expression.IntegralLiteral;
import org.odata4j.expression.NullLiteral;
import org.odata4j.expression.StringLiteral;
import com.fujitsu.dc.core.DcCoreException;
import com.fujitsu.dc.core.utils.ODataUtils;
/**
* $filterクエリの検索条件に指定するプロパティのデータ型と検索条件の値として指定されたデータ型の整合性を検証するクラス.
*/
public class FilterConditionValidator {
private static Map<EdmSimpleType<?>, AbstractValidator> validatorMap;
/**
* データ型検証用クラスの初期化.
*/
static {
validatorMap = new HashMap<EdmSimpleType<?>, AbstractValidator>();
validatorMap.put(EdmSimpleType.STRING, new StringValidator());
validatorMap.put(EdmSimpleType.BOOLEAN, new BooleanValidator());
validatorMap.put(EdmSimpleType.INT32, new Int32Validator());
validatorMap.put(EdmSimpleType.SINGLE, new SingleValidator());
validatorMap.put(EdmSimpleType.DOUBLE, new DoubleValidator());
validatorMap.put(EdmSimpleType.DATETIME, new DateTimeValidator());
}
private FilterConditionValidator() {
}
/**
* $filterクエリの検索条件に指定するプロパティのデータ型と検索条件の値として指定されたデータ型の整合性を検証する.
* <ul>
* <li>StringLiteral</li>
* <li>IntegralLiteral、Int64Literal</li>
* <li>DoubleLiteral</li>
* </ul>
* なお、"1.0f" や "1.0m" などの表記(それぞれSingleLiteral、DecimalLiteral)はパースエラーとする。
* @param edmProperty $filterの検索条件に指定されたプロパティ
* @param searchValue $filterの検索条件の値
*/
static void validateFilterOpCondition(EdmProperty edmProperty, CommonExpression searchValue) {
// 比較演算子(lt/le/ge/gt)共通で許容するデータ: 文字列/整数値/実数値
// 真偽値やNULLは大小比較ができないため、許容しない。
if (searchValue instanceof BooleanLiteral
|| searchValue instanceof NullLiteral) {
throw DcCoreException.OData.FILTER_PARSE_ERROR;
}
// スキーマ定義されているプロパティのデータ型として検索条件の値が評価できることを検証する。
// ただし、スキーマ定義されていない場合は、検証できないので除外する。
if (edmProperty != null) {
AbstractValidator validator = validatorMap.get(edmProperty.getType());
if (null == validator) {
throw DcCoreException.OData.FILTER_PARSE_ERROR;
}
validator.validate(searchValue, edmProperty.getName());
}
}
/**
* $filterクエリのEq演算子における検索条件に指定するプロパティのデータ型と検索条件の値として指定されたデータ型の整合性を検証する.
* <ul>
* <li>StringLiteral</li>
* <li>IntegralLiteral、Int64Literal</li>
* <li>DoubleLiteral</li>
* <li>BooleanLiteral</li>
* <li>NullLiteral</li>
* </ul>
* なお、"1.0f" や "1.0m" などの表記(それぞれSingleLiteral、DecimalLiteral)はパースエラーとする。
* @param edmProperty $filterの検索条件に指定されたプロパティ
* @param searchValue $filterの検索条件の値
*/
static void validateFilterEqCondition(EdmProperty edmProperty, CommonExpression searchValue) {
// スキーマ定義されているプロパティのデータ型として検索条件の値が評価できることを検証する。
// ただし、スキーマ定義されていない場合は、検証できないので除外する。
if (edmProperty != null) {
AbstractValidator validator = validatorMap.get(edmProperty.getType());
if (null == validator) {
throw DcCoreException.OData.FILTER_PARSE_ERROR;
}
validator.validate(searchValue, edmProperty.getName());
}
}
/**
* $filterクエリの関数に指定するプロパティのデータ型と値として指定されたデータ型の整合性を検証する.
* <ul>
* <li>StringLiteral</li>
* </ul>
* @param edmProperty $filterの関数に指定されたプロパティ
* @param searchValue $filterの関数に指定された値
*/
static void validateFilterFuncCondition(EdmProperty edmProperty, CommonExpression searchValue) {
// 関数(substringof/startswith)共通で許容するデータ: 文字列
if (!(searchValue instanceof StringLiteral)) {
throw DcCoreException.OData.OPERATOR_AND_OPERAND_TYPE_MISMATCHED.params(edmProperty.getName());
}
// スキーマ定義されているプロパティのデータ型として検索条件の値が評価できることを検証する。
// ただし、スキーマ定義されていない場合は、検証できないので除外する。
if (edmProperty != null
&& !EdmSimpleType.STRING.getFullyQualifiedTypeName().equals(
edmProperty.getType().getFullyQualifiedTypeName())) {
throw DcCoreException.OData.OPERATOR_AND_OPERAND_TYPE_MISMATCHED.params(edmProperty.getName());
}
}
/**
* 検索条件に指定された各データ型の型検証クラスととりまとめる抽象クラス.
*/
interface AbstractValidator {
/**
* 検索条件に指定されたプロパティのデータ型と検索条件値のデータとの不整合を検証する.
* @param searchValue 検索条件値
* @param propertyName 検索対象のプロパティ名
*/
void validate(CommonExpression searchValue, String propertyName);
}
/**
* 検索条件に指定されたEdm.String型の型検証クラス.
*/
static class StringValidator implements AbstractValidator {
@Override
public void validate(CommonExpression searchValue, String propertyName) {
if (searchValue instanceof StringLiteral
|| searchValue instanceof NullLiteral) {
return;
}
throw DcCoreException.OData.OPERATOR_AND_OPERAND_TYPE_MISMATCHED.params(propertyName);
}
}
/**
* 検索条件に指定されたEdm.Boolean型の型検証クラス.
*/
static class BooleanValidator implements AbstractValidator {
@Override
public void validate(CommonExpression searchValue, String propertyName) {
if (searchValue instanceof BooleanLiteral
|| searchValue instanceof NullLiteral) {
return;
}
throw DcCoreException.OData.OPERATOR_AND_OPERAND_TYPE_MISMATCHED.params(propertyName);
}
}
/**
* 検索条件に指定されたEdm.Int32型の型検証クラス.
*/
static class Int32Validator implements AbstractValidator {
@Override
public void validate(CommonExpression searchValue, String propertyName) {
long value = 0L; // odata4jのInt64Literal#gerValueがlong型の値を返すためvalueはlong型とした。
if (searchValue instanceof IntegralLiteral) {
value = ((IntegralLiteral) searchValue).getValue();
} else if (searchValue instanceof Int64Literal) {
value = ((Int64Literal) searchValue).getValue();
} else if (searchValue instanceof NullLiteral) {
value = 0;
} else {
throw DcCoreException.OData.OPERATOR_AND_OPERAND_TYPE_MISMATCHED.params(propertyName);
}
// 値の範囲チェック
if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) {
throw DcCoreException.OData.UNSUPPORTED_OPERAND_FORMAT.params(propertyName);
}
}
}
/**
* 検索条件に指定されたEdm.Double型の型検証クラス.
*/
static class DoubleValidator implements AbstractValidator {
@Override
public void validate(CommonExpression searchValue, String propertyName) {
if (searchValue instanceof IntegralLiteral
|| searchValue instanceof Int64Literal
|| searchValue instanceof DoubleLiteral
|| searchValue instanceof NullLiteral) {
return;
}
throw DcCoreException.OData.OPERATOR_AND_OPERAND_TYPE_MISMATCHED.params(propertyName);
}
}
/**
* 検索条件に指定されたEdm.Single型の型検証クラス.
*/
static class SingleValidator implements AbstractValidator {
@Override
public void validate(CommonExpression searchValue, String propertyName) {
double value = 0D; // odata4jのDoubleLiteral#gerValueがdouble型の値を返すためvalueはdouble型とした。
if (searchValue instanceof IntegralLiteral) {
value = ((IntegralLiteral) searchValue).getValue();
} else if (searchValue instanceof Int64Literal) {
value = ((Int64Literal) searchValue).getValue();
} else if (searchValue instanceof DoubleLiteral) {
value = ((DoubleLiteral) searchValue).getValue();
} else if (searchValue instanceof NullLiteral) {
value = 0;
} else {
throw DcCoreException.OData.OPERATOR_AND_OPERAND_TYPE_MISMATCHED.params(propertyName);
}
// 値の範囲チェック
if (!ODataUtils.validateSingle(String.valueOf(value))) {
throw DcCoreException.OData.UNSUPPORTED_OPERAND_FORMAT.params(propertyName);
}
}
}
/**
* 検索条件に指定されたEdm.DateTime型の型検証クラス.
*/
static class DateTimeValidator implements AbstractValidator {
@Override
public void validate(CommonExpression searchValue, String propertyName) {
long value = 0L; // odata4jのInt64Literal#gerValueがlong型の値を返すためvalueはlong型とした。
if (searchValue instanceof IntegralLiteral) {
value = ((IntegralLiteral) searchValue).getValue();
} else if (searchValue instanceof Int64Literal) {
value = ((Int64Literal) searchValue).getValue();
} else if (searchValue instanceof NullLiteral) {
value = 0;
} else {
throw DcCoreException.OData.OPERATOR_AND_OPERAND_TYPE_MISMATCHED.params(propertyName);
}
// 値の範囲チェック
if (value > ODataUtils.DATETIME_MAX || value < ODataUtils.DATETIME_MIN) {
throw DcCoreException.OData.UNSUPPORTED_OPERAND_FORMAT.params(propertyName);
}
}
}
}