blob: 6e5cb5ca961028ea22716a05f1afd436f78804ea [file] [log] [blame]
/*
* 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.eagle.log.entity;
import org.apache.eagle.log.entity.meta.EntityDefinition;
import org.apache.eagle.log.entity.meta.EntityDefinitionManager;
import org.apache.eagle.log.entity.meta.EntitySerDeser;
import org.apache.eagle.log.entity.meta.Qualifier;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.hadoop.hbase.KeyValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class EntityQualifierUtils {
private final static Logger LOG = LoggerFactory.getLogger(EntityQualifierUtils.class);
public static Map<String,Object> keyValuesToMap(List<KeyValue> row,EntityDefinition ed){
Map<String,Object> result = new HashMap<String,Object>();
for(KeyValue kv:row){
String qualifierName = new String(kv.getQualifier());
if(!ed.isTag(qualifierName)){
Qualifier qualifier = ed.getDisplayNameMap().get(qualifierName);
if(qualifier == null){
qualifier = ed.getQualifierNameMap().get(qualifierName);
}
qualifierName = qualifier.getDisplayName();
Object value = qualifier.getSerDeser().deserialize(kv.getValue());
result.put(qualifierName,value);
}else{
result.put(qualifierName,new String(kv.getValue()));
}
}
return result;
}
public static Map<String,Double> keyValuesToDoubleMap(List<KeyValue> row,EntityDefinition ed){
Map<String,Double> result = new HashMap<String,Double>();
for(KeyValue kv:row){
String qualifierName = new String(kv.getQualifier());
if(!ed.isTag(qualifierName)){
Qualifier qualifier = ed.getDisplayNameMap().get(qualifierName);
if(qualifier == null){
qualifier = ed.getQualifierNameMap().get(qualifierName);
}
qualifierName = qualifier.getDisplayName();
Object value = qualifier.getSerDeser().deserialize(kv.getValue());
result.put(qualifierName,convertObjToDouble(value));
}else{
result.put(qualifierName,Double.NaN);
}
}
return result;
}
/**
* Map[Display Name,Double Value]
*
* @param map
* @param ed
* @return
*/
public static Map<String,Double> bytesMapToDoubleMap(Map<String,byte[]> map,EntityDefinition ed){
Map<String,Double> result = new HashMap<String,Double>();
for(Map.Entry<String,byte[]> entry:map.entrySet()){
String qualifierName = entry.getKey();
Qualifier qualifier = ed.getDisplayNameMap().get(qualifierName);
if(qualifier == null) qualifier = ed.getQualifierNameMap().get(qualifierName);
if(qualifier!=null && entry.getValue()!=null) {
qualifierName = qualifier.getDisplayName();
Object value = qualifier.getSerDeser().deserialize(entry.getValue());
result.put(qualifierName, convertObjToDouble(value));
}else{
result.put(qualifierName,null);
}
}
return result;
}
public static byte[] toBytes(EntityDefinition ed, String qualifierName, String qualifierValueInStr){
// Get field type from entity class
// and skip for not-found fields query expression
Object typedValue = null;
EntitySerDeser serDeser = null;
if(ed.isTag(qualifierName)){
typedValue = qualifierValueInStr;
serDeser = EntityDefinitionManager.getSerDeser(String.class);
}else{
try{
Field field = ed.getEntityClass().getDeclaredField(qualifierName);
Class<?> fieldType = field.getType();
serDeser = EntityDefinitionManager.getSerDeser(fieldType);
if(serDeser == null){
throw new IllegalArgumentException("Can't find EntitySerDeser for field: "+ qualifierName +"'s type: "+fieldType
+", so the field is not supported to be filtered yet");
}
typedValue = convertStringToObject(qualifierValueInStr, fieldType);
} catch (NoSuchFieldException ex) {
// Handle the field not found exception in caller
LOG.error("Field " + qualifierName + " not found in " + ed.getEntityClass());
throw new IllegalArgumentException("Field "+qualifierName+" not found in "+ed.getEntityClass(),ex);
}
}
return serDeser.serialize(typedValue);
}
public static Class<?> getType(EntityDefinition ed, String qualifierName) {
Field field;
try {
field = ed.getEntityClass().getDeclaredField(qualifierName);
} catch (NoSuchFieldException e) {
if(LOG.isDebugEnabled()) LOG.debug("Field "+qualifierName+" not found in "+ed.getEntityClass());
return null;
}
return field.getType();
}
/**
* Not support negative numeric value:
* - http://en.wikipedia.org/wiki/Double-precision_floating-point_format
*
* @param value
* @param type
* @return
*/
public static Object convertStringToObject(String value, Class<?> type){
Object obj = null;
try{
if(String.class.equals(type)){
obj = value;
}if(Long.class.equals(type) || long.class.equals(type)){
obj = Long.parseLong(value);
// if((Long) obj < 0) throw new IllegalArgumentException("Don't support negative Long yet: "+obj);
}else if(Integer.class.equals(type) || int.class.equals(type)){
obj = Integer.parseInt(value);
// if((Integer) obj < 0) throw new IllegalArgumentException("Don't support negative Integer yet: "+obj);
}else if(Double.class.equals(type) || double.class.equals(type)){
obj = Double.parseDouble(value);
// if((Double) obj < 0) throw new IllegalArgumentException("Don't support negative Double yet: "+obj);
}else if(Float.class.equals(type) || float.class.equals(type)){
obj = Float.parseFloat(value);
// if((Double) obj < 0) throw new IllegalArgumentException("Don't support negative Float yet: "+obj);
}else if(Boolean.class.equals(type) || boolean.class.equals(type)) {
obj = Boolean.valueOf(value);
}
if(obj != null) return obj;
}catch (NumberFormatException ex){
throw new IllegalArgumentException("Fail to convert string: "+value +" into type of "+type,ex);
}
throw new IllegalArgumentException("Fail to convert string: "+value +" into type of "+type+", illegal type: "+type);
}
/**
*
* @param obj
* @return double value, otherwise Double.NaN
*/
public static double convertObjToDouble(Object obj){
if(Long.class.equals(obj.getClass()) || long.class.equals(obj.getClass())){
Long _value = (Long) obj;
return _value.doubleValue();
}else if(Integer.class.equals(obj.getClass()) || int.class.equals(obj.getClass())){
Integer _value = (Integer) obj;
return _value.doubleValue();
}else if(Double.class.equals(obj.getClass()) || double.class.equals(obj.getClass())) {
return (Double) obj;
}else if(Float.class.equals(obj.getClass()) || float.class.equals(obj.getClass())) {
Float _value = (Float) obj;
return _value.doubleValue();
}else if(Short.class.equals(obj.getClass()) || short.class.equals(obj.getClass())) {
Float _value = (Float) obj;
return _value.doubleValue();
}else if(Byte.class.equals(obj.getClass()) || byte.class.equals(obj.getClass())) {
Byte _value = (Byte) obj;
return _value.doubleValue();
}
LOG.warn("Failed to convert object " + obj.toString() + " in type of " + obj.getClass() + " to double");
return Double.NaN;
}
/**
* Parse List String as Set without duplicate items
*
* <br></br>
* Support:
* <ul>
* <li>normal string: ("a","b") => ["a","b"] </li>
* <li>number: (1.5,"b") => [1.5,"b"] </li>
* <li>inner string comma: ("va,lue","value",",") => ["va,lue","value",","]</li>
* <li>inner escaped chars: ("va\"lue","value") => ["va\"lue","value"]</li>
* <li>some bad formats list: ("va"lue","value") => ["va\"lue","value"]</li>
* </ul>
*
* <b>Warning:</b> it will not throw exception if the format is not strictly valid
*
* @param listValue in format (item1,item2,...)
* @return
*/
public static List<String> parseList(String listValue){
Matcher matcher = SET_PATTERN.matcher(listValue);
if(matcher.find()){
String content = matcher.group(1);
List<String> result = new ArrayList<String>();
StringBuilder str = null;
STATE state = null;
char last = 0;
for(char c: content.toCharArray()){
if(str == null) str = new StringBuilder();
if(c == DOUBLE_QUOTE && last != SLASH){
// Open or Close String
if(state == STATE.STRING)
state = null;
else state = STATE.STRING;
}else if(c == COMMA && state != STATE.STRING){
result.add(unescape(str.toString()));
str = null;
last = c;
continue;
}
last = c;
str.append(c);
}
if(str!=null) result.add(unescape(str.toString()));
return result;
}else{
LOG.error("Invalid list value: " + listValue);
throw new IllegalArgumentException("Invalid format of list value: "+listValue+", must be in format: (item1,item2,...)");
}
}
private static String unescape(String str){
int start=0,end = str.length();
if(str.startsWith("\"")) start = start +1;
if(str.endsWith("\"")) end = end -1;
str = str.substring(start,end);
return StringEscapeUtils.unescapeJava(str);
}
private final static Pattern SET_PATTERN = Pattern.compile("^\\((.*)\\)$");
private final static char COMMA = ',';
private final static char DOUBLE_QUOTE = '"';
private final static char SLASH = '\\';
private static enum STATE{ STRING }
// TODO: NOT FINISHED
// private final static Map<String,String> ESCAPE_REGEXP=new HashMap<String,String>(){{
// this.put("\\.","\\\\.");
// }};
//
// public static String escapeRegExp(String value) {
// String _value = value;
// for(Map.Entry<String,String> entry:ESCAPE_REGEXP.entrySet()){
// _value = _value.replace(entry.getKey(),entry.getValue());
// }
// return _value;
// }
}