/* * 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.mongodb.utils; 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.bson.BSONObject; import org.bson.BasicBSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; 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.utils.AnnotationUtils; import com.stratio.deep.commons.utils.Utils; /** * Several utilities to work used in the Spark <=> MongoDB integration. */ public final class UtilMongoDB { /** * The constant MONGO_DEFAULT_ID. */ public static final String MONGO_DEFAULT_ID = "_id"; /** * The constant LOG. */ private static final Logger LOG = LoggerFactory.getLogger(UtilMongoDB.class); /** * Private default constructor. */ private UtilMongoDB() { throw new UnsupportedOperationException(); } /** * converts from BsonObject to an entity class with deep's anotations * * @param classEntity the entity name. * @param bsonObject the instance of the BSONObjet to convert. * @return the provided bsonObject converted to an instance of T. * @throws IllegalAccessException the illegal access exception * @throws IllegalAccessException the instantiation exception * @throws IllegalAccessException the invocation target exception */ public static <T> T getObjectFromBson(Class<T> classEntity, BSONObject bsonObject) throws IllegalAccessException, InstantiationException, InvocationTargetException { T t = classEntity.newInstance(); Field[] fields = AnnotationUtils.filterDeepFields(classEntity); Object insert = null; for (Field field : fields) { Object currentBson = null; Method method = null; try { method = Utils.findSetter(field.getName(), classEntity, field.getType()); Class<?> classField = field.getType(); currentBson = bsonObject.get(AnnotationUtils.deepFieldName(field)); if (currentBson != null) { if (Iterable.class.isAssignableFrom(classField)) { Type type = field.getGenericType(); insert = subDocumentListCase(type, (List) bsonObject.get(AnnotationUtils.deepFieldName(field))); } else if (IDeepType.class.isAssignableFrom(classField)) { insert = getObjectFromBson(classField, (BSONObject) bsonObject.get(AnnotationUtils.deepFieldName (field))); } else { insert = currentBson; } method.invoke(t, insert); } } catch (IllegalAccessException | InstantiationException | InvocationTargetException | IllegalArgumentException e) { LOG.error("impossible to create a java object from Bson field:" + field.getName() + " and type:" + field .getType() + " and value:" + t + "; bsonReceived:" + currentBson + ", bsonClassReceived:" + currentBson.getClass()); method.invoke(t, Utils.castNumberType(insert, t.getClass())); } } return t; } /** * Sub document list case. * * @param <T> the type parameter * @param type the type * @param bsonOject the bson oject * @return the object * @throws IllegalAccessException the illegal access exception * @throws InstantiationException the instantiation exception * @throws InvocationTargetException the invocation target exception */ private static <T> Object subDocumentListCase(Type type, List<T> bsonOject) throws IllegalAccessException, InstantiationException, InvocationTargetException { ParameterizedType listType = (ParameterizedType) type; Class<?> listClass = (Class<?>) listType.getActualTypeArguments()[0]; List list = new ArrayList(); for (T t : bsonOject) { list.add(getObjectFromBson(listClass, (BSONObject) t)); } return list; } /** * converts from an entity class with deep's anotations to BsonObject. * * @param t an instance of an object of type T to convert to BSONObject. * @return the provided object converted to BSONObject. * @throws IllegalAccessException the illegal access exception * @throws IllegalAccessException the instantiation exception * @throws IllegalAccessException the invocation target exception */ public static <T> DBObject getBsonFromObject(T t) throws IllegalAccessException, InstantiationException, InvocationTargetException { Field[] fields = AnnotationUtils.filterDeepFields(t.getClass()); DBObject bson = new BasicDBObject(); 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 innerBsonList = new ArrayList<>(); while (iterator.hasNext()) { innerBsonList.add(getBsonFromObject(iterator.next())); } bson.put(AnnotationUtils.deepFieldName(field), innerBsonList); } else if (IDeepType.class.isAssignableFrom(field.getType())) { bson.put(AnnotationUtils.deepFieldName(field), getBsonFromObject((IDeepType) object)); } else { bson.put(AnnotationUtils.deepFieldName(field), object); } } } return bson; } /** * returns the id value annotated with @DeepField(fieldName = "_id") * * @param t an instance of an object of type T to convert to BSONObject. * @return the provided object converted to Object. * @throws IllegalAccessException the illegal access exception * @throws IllegalAccessException the instantiation exception * @throws IllegalAccessException the invocation target exception */ public static <T extends IDeepType> Object getId(T t) throws IllegalAccessException, InstantiationException, InvocationTargetException { Field[] fields = AnnotationUtils.filterDeepFields(t.getClass()); for (Field field : fields) { if (MONGO_DEFAULT_ID.equals(AnnotationUtils.deepFieldName(field))) { return Utils.findGetter(field.getName(), t.getClass()).invoke(t); } } return null; } /** * converts from BsonObject to cell class with deep's anotations * * @param bsonObject the bson object * @param tableName the table name * @return cell from bson * @throws IllegalAccessException the illegal access exception * @throws IllegalAccessException the instantiation exception * @throws IllegalAccessException the invocation target exception */ public static Cells getCellFromBson(BSONObject bsonObject, String tableName) { Cells cells = tableName != null ? new Cells(tableName) : new Cells(); Map<String, Object> map = bsonObject.toMap(); Set<Map.Entry<String, Object>> entryBson = map.entrySet(); for (Map.Entry<String, Object> entry : entryBson) { try { if (List.class.isAssignableFrom(entry.getValue().getClass())) { List innerCell = new ArrayList<>(); for (Object innerBson : (List)entry.getValue()) { if(innerBson instanceof DBObject){ innerCell.add(getCellFromBson((DBObject)innerBson, null)); }else{ innerCell.add(innerBson); } } cells.add(Cell.create(entry.getKey(), innerCell)); } else if (BSONObject.class.isAssignableFrom(entry.getValue().getClass())) { Cells innerCells = getCellFromBson((BSONObject) entry.getValue(), null); cells.add(Cell.create(entry.getKey(), innerCells)); } else { cells.add(Cell.create(entry.getKey(), entry.getValue())); } } catch (IllegalArgumentException e) { LOG.error("impossible to create a java cell from Bson field:" + entry.getKey() + ", type:" + entry .getValue().getClass() + ", value:" + entry.getValue()); } } return cells; } /** * converts from and entity class with deep's anotations to BsonObject * * @param cells the cells * @return bson from cell */ public static DBObject getDBObjectFromCell(Cells cells) { DBObject bson = new BasicDBObject(); for (Cell cell : cells) { if (cell.getValue() != null) { if (Collection.class.isAssignableFrom(cell.getCellValue().getClass())) { Collection c = (Collection) cell.getCellValue(); Iterator iterator = c.iterator(); List<Object> innerBsonList = new ArrayList<>(); while (iterator.hasNext()) { Object currentO = iterator.next(); if(currentO instanceof Cells){ innerBsonList.add(getDBObjectFromCell((Cells) currentO)); }else{ innerBsonList.add(currentO); } } bson.put(cell.getCellName(), innerBsonList); } else if (Cells.class.isAssignableFrom(cell.getCellValue().getClass())) { bson.put(cell.getCellName(), getDBObjectFromCell((Cells) cell.getCellValue())); } else { bson.put(cell.getCellName(), cell.getCellValue()); } } } return bson; } }