/*
* Copyright 2014, Stratio.
*
* 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 com.stratio.deep.es.utils;
/**
* Several utilities to work used in the Spark <=> ElasticSearch integration.
*/
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.hadoop.io.ArrayWritable;
import org.apache.hadoop.io.BooleanWritable;
import org.apache.hadoop.io.ByteWritable;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.FloatWritable;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
import org.elasticsearch.hadoop.mr.LinkedMapWritable;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.json.simple.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.stratio.deep.commons.entity.Cell;
import com.stratio.deep.commons.entity.Cells;
import com.stratio.deep.commons.entity.IDeepType;
import com.stratio.deep.commons.filter.Filter;
import com.stratio.deep.commons.filter.FilterType;
import com.stratio.deep.commons.utils.AnnotationUtils;
import com.stratio.deep.commons.utils.Utils;
/**
* Created by rcrespo on 29/07/14.
*/
public final class UtilES {
private static final Logger LOG = LoggerFactory.getLogger(UtilES.class);
/**
* Private default constructor.
*/
private UtilES() {
throw new UnsupportedOperationException();
}
/**
* converts from JSONObject to an entity class with deep's anotations
*
* @param classEntity the entity name.
* @param jsonObject the instance of the JSONObject to convert.
* @param <T> return type.
* @return the provided JSONObject converted to an instance of T.
* @throws IllegalAccessException
* @throws InstantiationException
* @throws java.lang.reflect.InvocationTargetException
*/
public static <T> T getObjectFromJson(Class<T> classEntity, LinkedMapWritable jsonObject)
throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
T t = classEntity.newInstance();
Field[] fields = AnnotationUtils.filterDeepFields(classEntity);
Object insert;
for (Field field : fields) {
Method method = Utils.findSetter(field.getName(), classEntity, field.getType());
Class<?> classField = field.getType();
String key = AnnotationUtils.deepFieldName(field);
Text text = new org.apache.hadoop.io.Text(key);
Writable currentJson = jsonObject.get(text);
if (currentJson != null) {
if (Iterable.class.isAssignableFrom(classField)) {
Type type = field.getGenericType();
insert = subDocumentListCase(type, (ArrayWritable) currentJson);
method.invoke(t, (insert));
} else if (IDeepType.class.isAssignableFrom(classField)) {
insert = getObjectFromJson(classField, (LinkedMapWritable) currentJson);
method.invoke(t, (insert));
} else {
insert = currentJson;
try {
method.invoke(t, getObjectFromWritable((Writable) insert));
} catch (Exception e) {
LOG.error("impossible to convert field " + t + " :" + field + " error: " + e.getMessage());
method.invoke(t, Utils.castNumberType(getObjectFromWritable((Writable) insert), t.getClass()));
}
}
}
}
return t;
}
private static <T> Object subDocumentListCase(Type type, ArrayWritable arrayWritable)
throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
ParameterizedType listType = (ParameterizedType) type;
Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0];
List list = new ArrayList();
Writable[] writetable = arrayWritable.get();
for (int i = 0; i < writetable.length; i++) {
list.add(getObjectFromJson(listClass, (LinkedMapWritable) writetable[i]));
}
return list;
}
/**
* converts from an entity class with deep's anotations to JSONObject.
*
* @param t an instance of an object of type T to convert to JSONObject.
* @param <T> the type of the object to convert.
* @return the provided object converted to JSONObject.
* @throws IllegalAccessException
* @throws InstantiationException
* @throws InvocationTargetException
*/
public static <T> JSONObject getJsonFromObject(T t)
throws IllegalAccessException, InstantiationException, InvocationTargetException {
Field[] fields = AnnotationUtils.filterDeepFields(t.getClass());
JSONObject json = new JSONObject();
for (Field field : fields) {
Method method = Utils.findGetter(field.getName(), t.getClass());
Object object = method.invoke(t);
if (object != null) {
if (Collection.class.isAssignableFrom(field.getType())) {
Collection c = (Collection) object;
Iterator iterator = c.iterator();
List<JSONObject> innerJsonList = new ArrayList<>();
while (iterator.hasNext()) {
innerJsonList.add(getJsonFromObject((IDeepType) iterator.next()));
}
json.put(AnnotationUtils.deepFieldName(field), innerJsonList);
} else if (IDeepType.class.isAssignableFrom(field.getType())) {
json.put(AnnotationUtils.deepFieldName(field), getJsonFromObject((IDeepType) object));
} else {
json.put(AnnotationUtils.deepFieldName(field), object);
}
}
}
return json;
}
/**
* converts from an entity class with deep's anotations to JSONObject.
*
* @param t an instance of an object of type T to convert to JSONObject.
* @param <T> the type of the object to convert.
* @return the provided object converted to JSONObject.
* @throws IllegalAccessException
* @throws InstantiationException
* @throws InvocationTargetException
*/
public static <T> LinkedMapWritable getLinkedMapWritableFromObject(T t)
throws IllegalAccessException, InstantiationException, InvocationTargetException {
Field[] fields = AnnotationUtils.filterDeepFields(t.getClass());
LinkedMapWritable linkedMapWritable = new LinkedMapWritable();
for (Field field : fields) {
Method method = Utils.findGetter(field.getName(), t.getClass());
Object object = method.invoke(t);
if (object != null) {
if (Collection.class.isAssignableFrom(field.getType())) {
Collection c = (Collection) object;
Iterator iterator = c.iterator();
List<LinkedMapWritable> innerJsonList = new ArrayList<>();
while (iterator.hasNext()) {
innerJsonList.add(getLinkedMapWritableFromObject((IDeepType) iterator.next()));
}
// linkedMapWritable.put(new Text(AnnotationUtils.deepFieldName(field)), new
// LinkedMapWritable[innerJsonList.size()]);
} else if (IDeepType.class.isAssignableFrom(field.getType())) {
linkedMapWritable.put(new Text(AnnotationUtils.deepFieldName(field)),
getLinkedMapWritableFromObject((IDeepType) object));
} else {
linkedMapWritable
.put(new Text(AnnotationUtils.deepFieldName(field)), getWritableFromObject(object));
}
}
}
return linkedMapWritable;
}
/**
* returns the id value annotated with @DeepField(fieldName = "_id")
*
* @param t an instance of an object of type T to convert to JSONObject.
* @param <T> the type of the object to convert.
* @return the provided object converted to Object.
* @throws IllegalAccessException
* @throws InstantiationException
* @throws InvocationTargetException
*/
public static <T extends IDeepType> Object getId(T t)
throws IllegalAccessException, InstantiationException, InvocationTargetException {
// TODO : implement
return null;
}
/**
* converts from JSONObject to cell class
*
* @param jsonObject
* @return
* @throws IllegalAccessException
* @throws InstantiationException
* @throws InvocationTargetException
*/
public static Cells getCellFromJson(LinkedMapWritable jsonObject, String tableName) throws IllegalAccessException,
InstantiationException, InvocationTargetException, NoSuchMethodException {
Cells cells = tableName != null ? new Cells(tableName) : new Cells();
Set<Map.Entry<Writable, Writable>> entryJson = jsonObject.entrySet();
for (Map.Entry<Writable, Writable> entry : entryJson) {
if (LinkedMapWritable.class.isAssignableFrom(entry.getValue().getClass())) {
Cells innerCells = getCellFromJson((LinkedMapWritable) entry.getValue(), null);
cells.add(Cell.create(entry.getKey().toString(), innerCells));
} else if (ArrayWritable.class.isAssignableFrom(entry.getValue().getClass())) {
Writable[] writetable = ((ArrayWritable) entry.getValue()).get();
List innerCell = new ArrayList<>();
for (int i = 0; i < writetable.length; i++) {
if(writetable[i] instanceof LinkedMapWritable){
innerCell.add(getCellFromJson((LinkedMapWritable) writetable[i], null));
}else{
innerCell.add(getObjectFromWritable(entry.getValue()));
}
}
cells.add(Cell.create(entry.getKey().toString(), innerCell));
} else {
cells.add(Cell.create(entry.getKey().toString(), getObjectFromWritable(entry.getValue())));
}
}
return cells;
}
/**
* Returns the object inside Writable
*
* @param writable
* @return
* @throws IllegalAccessException
* @throws InstantiationException
* @throws InvocationTargetException
* @throws NoSuchMethodException
*/
private static Object getObjectFromWritable(Writable writable)
throws IllegalAccessException, InstantiationException, InvocationTargetException {
Object object = null;
if (writable instanceof NullWritable) {
object = NullWritable.get();
} else if (writable instanceof BooleanWritable) {
object = ((BooleanWritable) writable).get();
} else if (writable instanceof Text) {
object = writable.toString();
} else if (writable instanceof ByteWritable) {
object = ((ByteWritable) writable).get();
} else if (writable instanceof IntWritable) {
object = ((IntWritable) writable).get();
} else if (writable instanceof LongWritable) {
object = ((LongWritable) writable).get();
} else if (writable instanceof BytesWritable) {
object = ((BytesWritable) writable).getBytes();
} else if (writable instanceof DoubleWritable) {
object = ((DoubleWritable) writable).get();
} else if (writable instanceof FloatWritable) {
object = ((FloatWritable) writable).get();
} else {
// TODO : do nothing
}
return object;
}
/**
* Returns the object inside Writable
*
* @param object
* @return
* @throws IllegalAccessException
* @throws InstantiationException
* @throws InvocationTargetException
* @throws NoSuchMethodException
*/
private static Writable getWritableFromObject(Object object) {
Writable writable = null;
if (object instanceof String) {
writable = new Text(object.toString());
} else if (object instanceof Long) {
writable = new LongWritable((Long) object);
} else {
writable = new IntWritable((Integer) object);
}
// writable = writable!=null?writable:new Text("");
return writable;
}
/**
* converts from cell class to JSONObject
*
* @return
* @throws IllegalAccessException
* @throws InstantiationException
* @throws InvocationTargetException
*/
public static JSONObject getJsonFromCell(Cells cells)
throws IllegalAccessException, InstantiationException, InvocationTargetException {
JSONObject json = new JSONObject();
for (Cell cell : cells) {
if (cell.getCellValue() != null) {
if (Collection.class.isAssignableFrom(cell.getCellValue().getClass())) {
Collection c = (Collection) cell.getCellValue();
Iterator iterator = c.iterator();
List<JSONObject> innerJsonList = new ArrayList<>();
while (iterator.hasNext()) {
innerJsonList.add(getJsonFromCell((Cells) iterator.next()));
}
json.put(cell.getCellName(), innerJsonList);
} else if (Cells.class.isAssignableFrom(cell.getCellValue().getClass())) {
json.put(cell.getCellName(), getJsonFromCell((Cells) cell.getCellValue()));
} else {
json.put(cell.getCellName(), cell.getCellValue());
}
}
}
return json;
}
public static QueryBuilder generateQuery(Filter... filterArray) {
List<Filter> range = new ArrayList<>();
List<Filter> ne = new ArrayList<>();
List<Filter> is = new ArrayList<>();
BoolQueryBuilder qb = QueryBuilders.boolQuery();
for (Filter filter : filterArray) {
if (!filter.getFilterType().equals(FilterType.EQ) && !filter.getFilterType().equals(FilterType.NEQ)) {
range.add(filter);
} else if (filter.getFilterType().equals(FilterType.EQ)) {
is.add(filter);
} else {
ne.add(filter);
}
}
for (Filter filter : range) {
RangeQueryBuilder rangeQueryBuilder = QueryBuilders
.rangeQuery(filter.getField());
switch (filter.getFilterType()) {
case LT:
rangeQueryBuilder.lt(filter.getValue());
break;
case LTE:
rangeQueryBuilder.lte(filter.getValue());
break;
case GT:
rangeQueryBuilder.gt(filter.getValue());
break;
case GTE:
rangeQueryBuilder.gte(filter.getValue());
break;
default:
break;
}
qb.must(rangeQueryBuilder);
}
for (Filter filter : is) {
qb.must(QueryBuilders.matchQuery(filter.getField(), filter.getValue()));
}
for (Filter filter : ne) {
qb.mustNot(QueryBuilders.matchQuery(filter.getField(), filter.getValue()));
}
return qb;
}
}