/**
* 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 com.huawei.streaming.cql.executor;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.huawei.streaming.cql.exception.SemanticAnalyzerException;
import com.huawei.streaming.exception.ErrorCode;
import com.huawei.streaming.process.agg.aggregator.avg.AggregateAvg;
import com.huawei.streaming.process.agg.aggregator.avg.AggregateAvgFilter;
import com.huawei.streaming.process.agg.aggregator.count.AggregateCount;
import com.huawei.streaming.process.agg.aggregator.count.AggregateCountFilter;
import com.huawei.streaming.process.agg.aggregator.max.AggregateMax;
import com.huawei.streaming.process.agg.aggregator.max.AggregateMaxFilter;
import com.huawei.streaming.process.agg.aggregator.min.AggregateMin;
import com.huawei.streaming.process.agg.aggregator.min.AggregateMinFilter;
import com.huawei.streaming.process.agg.aggregator.sum.AggregateSum;
import com.huawei.streaming.process.agg.aggregator.sum.AggregateSumFilter;
import com.huawei.streaming.udfs.Day;
import com.huawei.streaming.udfs.StringConcat;
import com.huawei.streaming.udfs.DateDiff;
import com.huawei.streaming.udfs.DayofMonth;
import com.huawei.streaming.udfs.FromUnixTime;
import com.huawei.streaming.udfs.Hour;
import com.huawei.streaming.udfs.StringToLower;
import com.huawei.streaming.udfs.Minute;
import com.huawei.streaming.udfs.Month;
import com.huawei.streaming.udfs.Second;
import com.huawei.streaming.udfs.UDF;
import com.huawei.streaming.udfs.Abs;
import com.huawei.streaming.udfs.UDFAnnotation;
import com.huawei.streaming.udfs.CurrentTimeMillis;
import com.huawei.streaming.udfs.DateAdd;
import com.huawei.streaming.udfs.DateSub;
import com.huawei.streaming.udfs.StringLength;
import com.huawei.streaming.udfs.SubString;
import com.huawei.streaming.udfs.ToDecimal;
import com.huawei.streaming.udfs.ToBoolean;
import com.huawei.streaming.udfs.ToDate;
import com.huawei.streaming.udfs.ToDouble;
import com.huawei.streaming.udfs.ToFloat;
import com.huawei.streaming.udfs.ToInt;
import com.huawei.streaming.udfs.ToLong;
import com.huawei.streaming.udfs.ToString;
import com.huawei.streaming.udfs.ToTime;
import com.huawei.streaming.udfs.ToTimeStamp;
import com.huawei.streaming.udfs.StringTrim;
import com.huawei.streaming.udfs.StringToUpper;
import com.huawei.streaming.udfs.WeekOfYear;
import com.huawei.streaming.udfs.Year;
/**
* 本地函数注册
* <p/>
* 该类中的所有函数均以静态的形式初始化
* 保证只被初始化一次
* <p/>
* 这主要是为了避免多客户端同时使用场景下的函数冲突
*
*/
public class NativeFunctionRegistry
{
private static final Logger LOG = LoggerFactory.getLogger(NativeFunctionRegistry.class);
private static final String UDF_METHOD_NAME = "evaluate";
private static final Map<String, FunctionInfo> NATIVE_FUNCTIONS =
Collections.synchronizedMap(new LinkedHashMap<String, FunctionInfo>());
static
{
/*
* 类型转换函数
* 类型转换函数利用了对象中的valueof函数,
* 所以这就要求,每个数据类型都必须实现valueOf接口
* 这也是语义分析的时候,常量数据类型解析的需求。
*/
registerNativeUDF(ToString.class);
registerNativeUDF(ToInt.class);
registerNativeUDF(ToLong.class);
registerNativeUDF(ToFloat.class);
registerNativeUDF(ToDouble.class);
registerNativeUDF(ToBoolean.class);
registerNativeUDF(ToDate.class);
registerNativeUDF(ToTime.class);
registerNativeUDF(ToTimeStamp.class);
registerNativeUDF(ToDecimal.class);
/*
* 其他功能类函数
*/
registerNativeUDF(SubString.class);
registerNativeUDF(StringLength.class);
registerNativeUDF(StringTrim.class);
registerNativeUDF(StringConcat.class);
registerNativeUDF(StringToUpper.class);
registerNativeUDF(StringToLower.class);
/*
* 数学函数
*/
registerNativeUDF(Abs.class);
/*
* 时间类函数
*/
registerNativeUDF(Day.class);
registerNativeUDF(DayofMonth.class);
registerNativeUDF(Month.class);
registerNativeUDF(Year.class);
registerNativeUDF(Hour.class);
registerNativeUDF(Minute.class);
registerNativeUDF(Second.class);
registerNativeUDF(FromUnixTime.class);
registerNativeUDF(WeekOfYear.class);
registerNativeUDF(DateAdd.class);
registerNativeUDF(DateSub.class);
registerNativeUDF(DateDiff.class);
registerNativeUDF(CurrentTimeMillis.class);
registerNativeUDAF("avg", AggregateAvg.class, AggregateAvgFilter.class);
registerNativeUDAF("count", AggregateCount.class, AggregateCountFilter.class);
registerNativeUDAF("max", AggregateMax.class, AggregateMaxFilter.class);
registerNativeUDAF("min", AggregateMin.class, AggregateMinFilter.class);
registerNativeUDAF("sum", AggregateSum.class, AggregateSumFilter.class);
/*
* 表达式
* 函数中并不会直接使用
* 仅仅起到占位的作用
*/
registerNativeUDF("cast", ToString.class);
registerNativeUDF("case", Boolean.class, "case");
registerNativeUDF("when", Boolean.class, "when");
registerNativeUDF("previous", Boolean.class, "previous");
registerNativeUDF("in", Boolean.class, "in");
registerNativeUDF("like", Boolean.class, "like");
registerNativeUDF("between", Boolean.class, "between");
}
public static String getUdfMethodName()
{
return UDF_METHOD_NAME;
}
public static Map<String, FunctionInfo> getNativeFunctions()
{
return NATIVE_FUNCTIONS;
}
/**
* 注册静态系统函数
* <p/>
* 这个方法是提供给CQL接口用的。
*
*/
public static void registerNativeStaticUDF(String shortName, Class< ? > clazz, String methodName)
{
NATIVE_FUNCTIONS.put(shortName,
FunctionInfo.createUDFFunctionInfo(shortName, clazz, methodName, false, FunctionType.UDF));
}
/**
* 注册本地的系统函数
*
*/
private static void registerNativeUDF(Class< ? extends UDF> clazz)
{
UDFAnnotation annotation = clazz.getAnnotation(UDFAnnotation.class);
String funcitonName = annotation == null ? null : annotation.value();
if (funcitonName == null)
{
SemanticAnalyzerException exception =
new SemanticAnalyzerException(ErrorCode.FUNCTION_UNSPPORTED, "<NULL>");
LOG.error("Unsupport function.", exception);
}
registerNativeUDF(funcitonName, clazz);
}
/**
* 注册本地的系统函数
*
*/
private static void registerNativeUDF(String shortName, Class< ? > clazz)
{
if (isExtendsUDF(clazz))
{
NATIVE_FUNCTIONS.put(shortName,
FunctionInfo.createUDFFunctionInfo(shortName, clazz, UDF_METHOD_NAME, true, FunctionType.UDF));
}
else
{
SemanticAnalyzerException exception =
new SemanticAnalyzerException(ErrorCode.FUNCTION_ERROR_EXTENDS, clazz.getName());
LOG.error("User defined function {} not extend from UDF class.", clazz.getName(), exception);
}
}
/**
* 是否是本地方法
*
*/
public static boolean isExtendsUDF(Class< ? > functionClass)
{
Class< ? > superClass = functionClass.getSuperclass();
while (UDF.class != superClass)
{
superClass = superClass.getSuperclass();
if (superClass == Object.class)
{
return false;
}
}
return true;
}
/**
* 注册系统函数
*
*/
private static void registerNativeUDAF(String shortName, Class< ? > clazz, Class< ? > filterClazz)
{
NATIVE_FUNCTIONS.put(shortName,
FunctionInfo.createUDAFFunctionInfo(shortName, clazz, filterClazz, true, FunctionType.UDAF));
}
/**
* 注册系统函数
*
*/
private static void registerNativeUDF(String shortName, Class< ? > clazz, String methodName)
{
NATIVE_FUNCTIONS.put(shortName,
FunctionInfo.createUDFFunctionInfo(shortName, clazz, methodName, true, FunctionType.UDF));
}
}