/*
* Copyright 2013 Future Systems
*
* 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.query.parser;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.araqne.logdb.FunctionRegistry;
import org.araqne.logdb.QueryContext;
import org.araqne.logdb.QueryParseException;
import org.araqne.logdb.query.aggregator.*;
import org.araqne.logdb.query.aggregator.CorrelationCoefficient.CorrelationCoefficientReducer;
import org.araqne.logdb.query.expr.Expression;
import org.araqne.logdb.query.expr.Values;
public class AggregationParser {
private static final String AS = " as ";
private static Map<String, Class<? extends AggregationFunction>> t;
static {
t = new HashMap<String, Class<? extends AggregationFunction>>();
t.put("c", Count.class);
t.put("count", Count.class);
t.put("sum", Sum.class);
t.put("avg", Average.class);
t.put("first", First.class);
t.put("last", Last.class);
t.put("max", Max.class);
t.put("min", Min.class);
t.put("per_day", PerDay.class);
t.put("per_hour", PerHour.class);
t.put("per_minute", PerMinute.class);
t.put("per_second", PerSecond.class);
t.put("range", Range.class);
t.put("values", Values.class);
t.put("var", Variance.class);
t.put("varMapper", Variance.VarianceMapper.class);
t.put("varReducer", Variance.VarianceReducer.class);
t.put("stddev", StdDev.class);
t.put("stddevReducer", StdDev.StdDevReducer.class);
t.put("covar", Covariance.class);
t.put("covarMapper", Covariance.CovarianceMapper.class);
t.put("covarReducer", Covariance.CovarianceReducer.class);
t.put("correl", CorrelationCoefficient.class);
t.put("correlMapper", CorrelationCoefficient.CorrelationCoefficientMapper.class);
t.put("correlReducer", CorrelationCoefficient.CorrelationCoefficientReducer.class);
t.put("slope", Slope.class);
t.put("slopeMapper", Slope.SlopeMapper.class);
t.put("slopeReducer", Slope.SlopeReducer.class);
}
public static AggregationField parse(QueryContext context, String s,
Map<String, Class<? extends AggregationFunction>> funcTable, FunctionRegistry functionRegistry) {
// find 'as' keyword
String funcPart = s.trim();
String alias = null;
int p = QueryTokenizer.findKeyword(s, AS);
if (p > 0) {
funcPart = s.substring(0, p).trim();
alias = s.substring(p + AS.length()).trim();
}
// find aggregation function
AggregationFunction func = parseFunc(context, funcTable, funcPart, functionRegistry);
// build and return
AggregationField field = new AggregationField();
field.setName(alias != null ? alias : func.toString());
field.setFunction(func);
return field;
}
public static AggregationField parse(QueryContext context, String s, FunctionRegistry functionRegistry) {
return parse(context, s, t, functionRegistry);
}
private static AggregationFunction parseFunc(QueryContext context,
Map<String, Class<? extends AggregationFunction>> funcTable, String s, FunctionRegistry functionRegistry) {
int p = s.indexOf('(');
String funcName = s;
String argsToken = "";
if (p > 0) {
funcName = s.substring(0, p);
// TODO: check closing parens
argsToken = s.substring(p + 1, s.length() - 1);
}
List<String> argTokens = QueryTokenizer.parseByComma(argsToken);
List<Expression> exprs = new ArrayList<Expression>();
for (String argToken : argTokens) {
Expression expr = ExpressionParser.parse(context, argToken, functionRegistry);
exprs.add(expr);
}
// find function
Class<?> c = funcTable.get(funcName);
if (c == null){
//throw new QueryParseException("invalid-aggregation-function", -1, "function name token is [" + funcName + "]");
Map<String, String> params = new HashMap<String, String> ();
params.put("function", funcName);
params.put("value", s);
throw new QueryParseException("21702", -1 , -1 , params);
}
try {
return (AggregationFunction) c.getConstructors()[0].newInstance(exprs);
}catch( InvocationTargetException e){
Throwable t = e.getTargetException();
if(t instanceof QueryParseException){
Map<String, String> params = ((QueryParseException) t).getParams();
if(params == null)
params = new HashMap<String, String> ();
params.put("function", funcName);
params.put("value", s);
throw new QueryParseException(((QueryParseException) t).getType(),-1, -1, params);
}else {
Map<String, String> params = new HashMap<String, String> ();
params.put("function", funcName);
params.put("msg", t.getMessage());
params.put("value", s);
throw new QueryParseException("21703", -1, -1, params);
}
} catch (Throwable e) {
// throw new QueryParseException("cannot-create-aggregation-function", -1, e.getMessage());
Map<String, String> params = new HashMap<String, String> ();
params.put("function", funcName);
params.put("msg", e.getMessage());
throw new QueryParseException("21703", -1, -1, params);
}
}
}