blob: 47477600155a4997dc4880c936d7ee3b847ee1ca [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 static final 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;
int 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 static final Pattern SET_PATTERN = Pattern.compile("^\\((.*)\\)$");
private static final char COMMA = ',';
private static final char DOUBLE_QUOTE = '"';
private static final char SLASH = '\\';
private static enum STATE {
STRING
}
// TODO: NOT FINISHED
// private static final 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;
// }
}