/**
* Copyright 2014 Eediom Inc.
*
* 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 org.araqne.logdb.impl;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Provides;
import org.araqne.logdb.FunctionFactory;
import org.araqne.logdb.FunctionRegistry;
import org.araqne.logdb.QueryContext;
import org.araqne.logdb.QueryParseException;
import org.araqne.logdb.query.expr.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(name = "logdb-function-registry")
@Provides
public class FunctionRegistryImpl implements FunctionRegistry {
private final Logger slog = LoggerFactory.getLogger(FunctionRegistryImpl.class);
// function name to factory mappings
private ConcurrentHashMap<String, FunctionFactory> factories = new ConcurrentHashMap<String, FunctionFactory>();
private EmbeddedFunctionFactory embedded = new EmbeddedFunctionFactory();
public FunctionRegistryImpl() {
registerFactory(embedded);
}
@Override
public Set<String> getFunctionNames() {
return new HashSet<String>(factories.keySet());
}
@Override
public void registerFactory(FunctionFactory factory) {
for (String funcName : factory.getFunctionNames()) {
FunctionFactory old = factories.putIfAbsent(funcName, factory);
if (old != null)
slog.warn("araqne logdb: duplicated function [{}:{}] is ignored", factory, funcName);
else
slog.debug("araqne logdb: registered function [{}:{}]", factory, funcName);
}
}
@Override
public void unregisterFactory(FunctionFactory factory) {
for (String funcName : factory.getFunctionNames()) {
if (factories.remove(funcName, factory))
slog.debug("araqne logdb: unregistered function [{}:{}]", factory, funcName);
}
}
private static class EmbeddedFunctionFactory implements FunctionFactory {
private Map<String, Constructor<?>> constructors = new HashMap<String, Constructor<?>>();
public EmbeddedFunctionFactory() {
define("abs", Abs.class);
define("max", Max.class);
define("min", Min.class);
define("case", Case.class);
define("if", If.class);
define("concat", Concat.class);
define("str", ToString.class);
define("long", ToLong.class);
define("int", ToInt.class);
define("double", ToDouble.class);
define("date", ToDate.class);
define("epoch", Epoch.class);
define("string", ToString.class);
define("left", Left.class);
define("right", Right.class);
define("trim", Trim.class);
define("len", Len.class);
define("substr", Substr.class);
define("replace", StringReplace.class);
define("isnull", IsNull.class);
define("isnotnull", IsNotNull.class);
define("isnum", IsNum.class);
define("isstr", IsStr.class);
define("match", Match.class);
define("typeof", Typeof.class);
define("in", In.class);
define("ip", ToIp.class);
define("network", Network.class);
define("urldecode", UrlDecode.class);
define("lower", Lower.class);
define("upper", Upper.class);
define("dateadd", DateAdd.class);
define("now", Now.class);
define("datediff", DateDiff.class);
define("$", ContextReference.class);
define("guid", Guid.class);
define("seq", Seq.class);
define("ip2long", Ip2Long.class);
define("ip2int", Ip2Int.class);
define("long2ip", Long2Ip.class);
define("round", Round.class);
define("field", Field.class);
define("floor", Floor.class);
define("ceil", Ceil.class);
define("split", Split.class);
define("array", Array.class);
define("kvjoin", KvJoin.class);
define("valueof", ValueOf.class);
define("datetrunc", DateTrunc.class);
define("strjoin", StrJoin.class);
define("hash", Hash.class);
define("binary", ToBinary.class);
define("encode", ToBinary.class);
define("decode", Decode.class);
define("indexof", IndexOf.class);
define("contains", Contains.class);
define("rand", Rand.class);
define("randbytes", RandBytes.class);
define("frombase64", FromBase64.class);
define("tobase64", ToBase64.class);
define("encrypt", Encrypt.class);
define("decrypt", Decrypt.class);
define("zip", Zip.class);
define("unique", Unique.class);
define("flatten", Flatten.class);
define("format", Format.class);
define("groups", Groups.class);
define("signature", Signature.class);
define("mod", Mod.class);
define("nvl", Nvl.class);
define("whoami", Whoami.class);
define("not", Not.class);
define("datepart", DatePart.class);
define("xpath", Xpath.class);
define("daterange", DateRange.class);
define("log", Log.class);
define("log10", Log10.class);
define("pow", Pow.class);
define("sqrt", Sqrt.class);
define("exp", Exp.class);
define("sin", Sin.class);
define("cos", Cos.class);
define("tan", Tan.class);
define("asin", Asin.class);
define("acos", Acos.class);
define("atan", Atan.class);
}
private void define(String name, Class<?> clazz) {
try {
Constructor<?> c = clazz.getConstructor(QueryContext.class, List.class);
constructors.put(name, c);
} catch (Throwable t) {
}
}
@Override
public Set<String> getFunctionNames() {
return new HashSet<String>(constructors.keySet());
}
@Override
public Expression newFunction(QueryContext ctx, String name, List<Expression> exprs) {
Constructor<?> c = constructors.get(name);
if (c == null) {
// throw new QueryParseException("unsupported-function", -1,
// name);
Map<String, String> params = new HashMap<String, String>();
params.put("function", name);
throw new QueryParseException("90900", -1, -1, params);
}
try {
return (Expression) c.newInstance(ctx, exprs);
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof QueryParseException)
throw (QueryParseException) e.getTargetException();
else if (e.getTargetException() instanceof QueryParseException)
throw (QueryParseException) e.getTargetException();
else {
// throw new
// QueryParseException("cannot create function instance",
// -1, e.getTargetException().toString());
Map<String, String> params = new HashMap<String, String>();
params.put("function", name);
params.put("msg", e.getTargetException().toString());
throw new QueryParseException("90901", -1, -1, params);
}
} catch (QueryParseException e) {
throw e;
} catch (Throwable t) {
Map<String, String> params = new HashMap<String, String>();
params.put("function", name);
params.put("msg", t.toString());
// throw new
// QueryParseException("cannot create function instance", -1,
// t.toString());
throw new QueryParseException("90902", -1, -1, params);
}
}
}
@Override
public Expression newFunction(QueryContext ctx, String functionName, List<Expression> exprs) {
FunctionFactory ff = factories.get(functionName);
if (ff == null) {
// throw new QueryParseException("unsupported-function", -1,
// functionName);
Map<String, String> params = new HashMap<String, String>();
params.put("function", functionName);
throw new QueryParseException("90900", -1, -1, params);
}
return ff.newFunction(ctx, functionName, exprs);
}
}