/*
*
*/
package org.smartly.packages.mongo.impl.util;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.json.JSONArray;
import org.json.JSONObject;
import org.smartly.commons.cryptograph.SecurityMessageDigester;
import org.smartly.commons.logging.util.LoggingUtils;
import org.smartly.commons.util.*;
import org.smartly.packages.mongo.impl.IMongoConstants;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.regex.Pattern;
/**
* @author angelo.geminiani
*/
public class MongoUtils
implements IMongoConstants {
public static final int CASE_INSENSITIVE = Pattern.CASE_INSENSITIVE;
private static String SEP = "-";
private static String LIST = "list"; // actionscript list tag
private static final String[] ID_FIELDS = new String[]{"_id", "id", "uid", "index", "name"};
private MongoUtils() {
}
public static String createUUID() {
return UUID.randomUUID().toString().replace("-", "");
}
public static String createUUID(final int len) {
return RandomUtils.random(len, RandomUtils.CHARS_LOW_NUMBERS);
}
/**
* Return an ID based on date and time. i.e. "20010101_12:45:22".
*
* @return
*/
public static String createDateTimeId() {
final String datetime = FormatUtils.formatDate(DateUtils.now(),
FormatUtils.DEFAULT_DATEFORMAT.concat("_").
concat(FormatUtils.DEFAULT_TIMEFORMAT));
return datetime;
}
public static String createMD5Id(final Object id) {
try {
return SecurityMessageDigester.encodeMD5(null != id ? id.toString() : createUUID());
} catch (Exception ex) {
}
return createUUID();
}
public static boolean isEmpty(final DBObject object) {
return !(null != object && object.keySet().size() > 0);
}
public static boolean hasId(final DBObject object) {
return null != getId(object);
}
public static Object getId(final DBObject object) {
if (null != object) {
if (object.containsField(ID)) {
return object.get(ID);
}
}
return null;
}
public static String getIdAsString(final DBObject object) {
final Object id = getId(object);
return null != id ? id.toString() : "";
}
public static String concatId(final Object... items) {
final StringBuilder result = new StringBuilder();
for (final Object item : items) {
StringUtils.append(item, result, SEP);
}
return result.length() > 0
? result.toString().trim()
: createUUID();
}
public static String[] splitId(final String id) {
return StringUtils.split(id, SEP);
}
public static DBObject parseObject(final String jsontext) {
if (StringUtils.hasText(jsontext) && StringUtils.isJSON(jsontext)) {
final JsonWrapper wrapper = new JsonWrapper(jsontext);
return wrapper.isJSONArray()
? parseObject(wrapper.getJSONArray())
: parseObject(wrapper.getJSONObject());
}
return null;
}
public static DBObject parseObject(final JSONObject jsonObject) {
if (null == jsonObject) {
return null;
}
final BasicDBObject result = new BasicDBObject();
final Iterator<String> keys = jsonObject.keys();
while (keys.hasNext()) {
final String key = keys.next();
final Object value = jsonObject.opt(key);
if (null != value) {
if (value instanceof JSONObject) {
final DBObject item = parseObject((JSONObject) value);
if (null != item) {
result.put(key, item);
}
} else if (value instanceof JSONArray) {
final DBObject item = parseObject((JSONArray) value);
if (null != item) {
result.put(key, item);
}
} else {
result.put(key, value);
}
}
}
return result;
}
public static DBObject parseObject(final JSONArray jsonArray) {
if (null == jsonArray) {
return null;
}
final BasicDBList result = new BasicDBList();
if (null != jsonArray && jsonArray.length() > 0) {
for (int i = 0; i < jsonArray.length(); i++) {
final Object value = jsonArray.opt(i);
if (null != value) {
if (value instanceof JSONArray) {
final DBObject item = parseObject((JSONArray) value);
if (null != item) {
result.add(item);
}
} else if (value instanceof JSONObject) {
final DBObject item = parseObject((JSONObject) value);
if (null != item) {
result.add(item);
}
} else {
result.add(value);
}
}
}
}
return result;
}
/**
* Parse JSON object for a List.<br/>
* Actionscript may wrap lists in Objects with a 'list' field.
* i.e. {list:['hello','list']}
*
* @param jsontext
* @return
*/
public static List parseList(final String jsontext) {
final DBObject item = parseObject(jsontext);
if (item instanceof List) {
return (List) item;
} else {
final Object list = item.get(LIST);
if (list instanceof List) {
return (List) list;
}
}
return null;
}
/**
* Validate an object for JSON standard.
* Null or empty collections, empty array or empty maps are not allowed.
*
* @param value Value to validate
* @return
*/
public static boolean isValidJSONValue(final Object value) {
return !CollectionUtils.isEmpty(value);
}
//-- getter and setter --//
/**
* Return value of a complex DBObjects navigating its properties.
*
* @param instance BasicDBObject, BasicDBList. i.e. "items
* => [{"_id":"H","value":"1500"},{"_id":"W","value":"500"}]"
* @param path Propeties path. i.e. "items.H.value"
* @return
*/
public static Object getByPath(final DBObject instance,
final String path) {
try {
return getDeepValue(instance, path);
} catch (Exception e) {
}
return null;
}
public static Object putByPath(final DBObject instance,
final String path,
final Object value) {
try {
return setPathValue(instance, path, value);
} catch (Exception e) {
}
return null;
}
public static Object get(final DBObject object,
final String fieldName) {
return get(object, fieldName, null);
}
public static Object get(final DBObject object,
final String fieldName,
final Object defaultValue) {
Object result = null;
if (null != object && object.containsField(fieldName)) {
result = object.get(fieldName);
}
return null != result ? result : defaultValue;
}
public static String getOneString(final DBObject object,
final String[] fieldNames) {
return getOneString(object, fieldNames, "");
}
public static String getOneString(final DBObject object,
final String[] fieldNames,
final String defaultValue) {
if (null != object) {
for (final String fieldName : fieldNames) {
if (object.containsField(fieldName)) {
return StringUtils.toString(object.get(fieldName), defaultValue);
}
}
}
return defaultValue;
}
public static String getString(final DBObject object,
final String fieldName) {
return getString(object, fieldName, "");
}
public static String getString(final DBObject object,
final String fieldName,
final String defaultValue) {
if (null != object && object.containsField(fieldName)) {
return StringUtils.toString(object.get(fieldName), defaultValue);
}
return defaultValue;
}
public static boolean getBoolean(final DBObject object,
final String fieldName) {
return getBoolean(object, fieldName, false);
}
public static boolean getBoolean(final DBObject object,
final String fieldName, final boolean defaultValue) {
if (null != object && object.containsField(fieldName)) {
return ConversionUtils.toBoolean(object.get(fieldName), defaultValue);
}
return defaultValue;
}
public static long getLong(final DBObject object,
final String fieldName) {
return getLong(object, fieldName, 0L);
}
public static long getLong(final DBObject object,
final String fieldName, final long defaultValue) {
if (null != object && object.containsField(fieldName)) {
return ConversionUtils.toLong(object.get(fieldName), defaultValue);
}
return defaultValue;
}
public static int getInt(final DBObject object,
final String fieldName) {
return getInt(object, fieldName, 0);
}
public static int getInt(final DBObject object,
final String fieldName, final int defaultValue) {
if (null != object && object.containsField(fieldName)) {
return ConversionUtils.toInteger(object.get(fieldName), defaultValue);
}
return defaultValue;
}
public static double getDouble(final DBObject object,
final String fieldName) {
return getDouble(object, fieldName, -1, 0.0);
}
public static double getDouble(final DBObject object,
final String fieldName, final double defaultValue) {
return getDouble(object, fieldName, -1, defaultValue);
}
public static double getDouble(final DBObject object,
final String fieldName,
final int decimals,
final double defaultValue) {
if (null != object && object.containsField(fieldName)) {
return ConversionUtils.toDouble(object.get(fieldName), decimals,
defaultValue);
}
return defaultValue;
}
public static DBObject getDBObject(final DBObject object,
final String fieldName) {
return getDBObject(object, fieldName, new BasicDBObject());
}
public static DBObject getDBObject(final DBObject object,
final String fieldName, final DBObject defaultValue) {
if (null != object && object.containsField(fieldName)) {
final Object result = object.get(fieldName);
if (result instanceof DBObject) {
return (DBObject) result;
}
}
return defaultValue;
}
//-- LIST --//
public static List getList(final DBObject object,
final String fieldName) {
return getList(object, fieldName, new ArrayList());
}
public static List getList(final DBObject object,
final String fieldName,
final List defaultValue) {
if (null != object) {
if (object.containsField(fieldName)) {
final Object result = object.get(fieldName);
if (null != result) {
if (result instanceof List) {
return (List) result;
} else if (result instanceof Collection) {
return new LinkedList((Collection) result);
} else if (result.getClass().isArray()) {
return (List) CollectionUtils.addAll(new LinkedList<Object>(), (Object[]) result);
} else {
final List<Object> list = new ArrayList<Object>();
list.add(result);
return list;
}
}
} else {
// add missing field
object.put(fieldName, defaultValue);
}
}
return defaultValue;
}
public static Object remove(final DBObject object,
final String fieldName) {
if (object instanceof BasicDBObject) {
return ((BasicDBObject) object).removeField(fieldName);
}
return null;
}
public static int inc(final DBObject object,
final String fieldName, final int value) {
if (null != object) {
final int data = getInt(object, fieldName) + value;
object.put(fieldName, data);
return data;
}
return 0;
}
public static void put(final DBObject object,
final String key, final Object value) {
if (isValidJSONValue(value)) {
// valus is not null or empty collection
object.put(key, value);
} else {
// value is null or empty. REMOVED!
object.removeField(key);
}
}
// <editor-fold defaultstate="collapsed" desc=" merge, clone ">
/**
* Update target object with source values.
*
* @param source Source values
* @param target Target object
* @param excludeProperties Properties to exclude
*/
public static void update(final DBObject source,
final DBObject target,
final String[] excludeProperties) {
if (null != source && null != target) {
final Set<String> keys = source.keySet();
for (final String key : keys) {
if (!CollectionUtils.contains(excludeProperties, key)) {
put(target, key, get(source, key));
}
}
}
}
public static void merge(final Object source, final Object target,
final String... excludeProperties) {
if (null != source && null != target) {
if (source instanceof DBObject && target instanceof DBObject) {
merge((DBObject) source, (DBObject) target);
} else if (target instanceof DBObject) {
merge(source, (DBObject) target, excludeProperties);
}
}
}
public static void merge(final Object source, final DBObject target,
final String[] excludeProperties) {
if (null != source && null != target) {
final String[] keys = BeanUtils.getPropertyNames(source.getClass());
for (final String key : keys) {
if (!CollectionUtils.contains(excludeProperties, key)) {
mergeKey(key, source, target);
}
}
}
}
/**
* Merge properties of target with source.
*
* @param source
* @param target
*/
public static void merge(final DBObject source, final DBObject target,
final String[] excludeProperties) {
if (null != source && null != target) {
final Set<String> keys = source.keySet();
for (final String key : keys) {
if (!CollectionUtils.contains(excludeProperties, key)) {
mergeKey(key, source, target);
}
}
}
}
/**
* Add default properties to target if missing.
*
* @param defaults source
* @param target
* @param excludeProperties
*/
public static void defaults(final DBObject defaults,
final DBObject target,
final String[] excludeProperties) {
if (null != defaults && null != target) {
final Set<String> keys = defaults.keySet();
for (final String key : keys) {
if (!CollectionUtils.contains(excludeProperties, key)
&& !target.containsField(key)) {
mergeKey(key, defaults, target);
}
}
}
}
public static void defaults(final DBObject defaults,
final DBObject target,
final String[] excludeProperties,
final boolean deep) {
if (null != defaults && null != target) {
final Set<String> keys = defaults.keySet();
for (final String key : keys) {
if (!CollectionUtils.contains(excludeProperties, key)) {
if (deep || !target.containsField(key)) {
mergeKey(key, defaults, target, false); // does not overwrite existing primitive values
}
}
}
}
}
public static void mergeKey(final String key,
final Object source,
final DBObject target) {
mergeKey(key, source, target, true);
}
/**
* Merge single property from source to target.
*
* @param key
* @param source
* @param target
*/
public static void mergeKey(final String key,
final DBObject source,
final DBObject target) {
mergeKey(key, source, target, true);
}
public static void mergeKey(final String key,
final Object source,
final DBObject target,
final boolean overwrite) {
if (source instanceof DBObject) {
mergeKey(key, (DBObject) source, target);
} else {
final Object svalue = BeanUtils.getValueIfAny(source, key);
final Object tvalue = target.get(key);
if (null == tvalue || null == svalue) {
// add new value to target
target.put(key, svalue);
} else {
if (svalue instanceof DBObject) {
putValue(target, key, (DBObject) svalue, overwrite);
} else {
// SOURCE is NULL or other Type (String, int, Object...)
// only primitives are allowed
if (BeanUtils.isPrimitiveClass(svalue)) {
if (tvalue instanceof Collection) {
// TARGET is a Collection
((Collection) tvalue).add(svalue);
} else {
// add new value to target
if (overwrite || !target.containsField(key)) {
target.put(key, svalue);
}
}
}
}
}
}
}
public static void mergeKey(final String key,
final DBObject source,
final DBObject target,
final boolean overwrite) {
final Object svalue = source.get(key);
final Object tvalue = target.get(key);
if (null == tvalue || null == svalue) {
// add new value to target
target.put(key, svalue);
} else {
if (svalue instanceof Collection) {
// SOURCE is Collection
putValue(target, key, (Collection) svalue, overwrite);
} else if (svalue instanceof DBObject) {
putValue(target, key, (DBObject) svalue, overwrite);
} else {
// SOURCE is NULL or other Type (String, int, Object...)
if (tvalue instanceof Collection) {
// TARGET is a Collection
((Collection) tvalue).add(svalue);
} else {
// add new value to target
if (overwrite || !target.containsField(key)) {
target.put(key, svalue);
}
}
}
}
}
public static DBObject clone(final DBObject source,
final String[] excludeProperties) throws Exception {
final DBObject target = new BasicDBObject();
merge(source, target, excludeProperties);
return target;
}
// </editor-fold>
public static Pattern patternStartWith(final String value) {
return patternStartWith(value, CASE_INSENSITIVE);
}
public static Pattern patternStartWith(final String value, final Integer flags) {
return null != flags
? Pattern.compile("^".concat(value).concat(".*$"), flags)
: Pattern.compile("^".concat(value).concat(".*$"));
}
public static Pattern patternEndWith(final String value) {
return patternEndWith(value, CASE_INSENSITIVE);
}
public static Pattern patternEndWith(final String value, final Integer flags) {
return null != flags
? Pattern.compile(value.concat("$"), flags)
: Pattern.compile(value.concat("$"));
}
public static Pattern patternStartWithEndWith(final String startValue,
final String endValue) {
return patternStartWithEndWith(startValue, endValue, CASE_INSENSITIVE);
}
public static Pattern patternStartWithEndWith(final String startValue,
final String endValue, final Integer flags) {
return null != flags
? Pattern.compile("^".concat(startValue).concat("(.*)".concat(endValue).concat("$")), flags)
: Pattern.compile("^".concat(startValue).concat("(.*)".concat(endValue).concat("$")));
}
public static Pattern patternContains(final String value) {
return patternContains(value, CASE_INSENSITIVE);
}
public static Pattern patternContains(final String value,
final Integer flags) {
return null != flags
? Pattern.compile("^.*".concat(value).concat(".*$"), flags)
: Pattern.compile("^.*".concat(value).concat(".*$"));
}
public static Pattern patternEquals(final String value) {
return patternEquals(value, CASE_INSENSITIVE);
}
public static Pattern patternEquals(final String value,
final Integer flags) {
return null != flags
? Pattern.compile("\\A".concat(value).concat("\\z"), flags)
: Pattern.compile("\\A".concat(value).concat("\\z"));
}
public static boolean queryIsOR(final DBObject query) {
if (null != query) {
return null != query.get(OP_OR);
}
return false;
}
public static DBObject queryEquals(final String field,
final Object value) {
return queryEquals(field, value, CASE_INSENSITIVE);
}
public static DBObject queryEquals(final String field,
final Object value,
final int flags) {
final DBObject query = new BasicDBObject();
return queryEquals(query, field, value, flags);
}
/**
* { x : "a" }<br/>
* { x : { $in : [ null ] } }<br/>
* { x : { $in : [ a, b ] } }<br/>
*
* @param field
* @param value
* @return
*/
public static DBObject queryEquals(final DBObject query,
final String field,
final Object value,
final int flags) {
if (null == value) {
// {"z" : {"$in" : [null], "$exists" : true}}
final DBObject condition = new BasicDBObject();
condition.put(OP_IN, new Object[]{null});
condition.put(OP_EXISTS, true);
query.put(field, condition);
} else if (value instanceof Collection) {
// { x : { $in : [ a, b ] } }
final Collection lvalue = (Collection) value;
final DBObject condition = new BasicDBObject();
condition.put(OP_IN, lvalue.toArray(new Object[lvalue.size()]));
//condition.put(OP_EXISTS, true);
query.put(field, condition);
} else if (value.getClass().isArray()) {
// { x : { $in : [ a, b ] } }
final Object[] lvalue = (Object[]) value;
final DBObject condition = new BasicDBObject();
condition.put(OP_IN, lvalue);
//condition.put(OP_EXISTS, true);
query.put(field, condition);
} else {
final Pattern pattern = patternEquals(value.toString(), flags);
query.put(field, pattern);
}
return query;
}
public static DBObject queryNotNull(final String field) {
return queryNotNull(new BasicDBObject(), field);
}
public static DBObject queryNotNull(final DBObject query,
final String field) {
final DBObject condition = new BasicDBObject();
condition.put(OP_NIN, new Object[]{null});
condition.put(OP_EXISTS, true);
query.put(field, condition);
return query;
}
public static DBObject queryNotEmpty(final String field) {
return queryNotEmpty(new BasicDBObject(), field);
}
public static DBObject queryNotEmpty(final DBObject query,
final String field) {
final DBObject condition = new BasicDBObject();
condition.put(OP_NIN, new Object[]{null, ""});
condition.put(OP_EXISTS, true);
query.put(field, condition);
return query;
}
public static DBObject queryNotEquals(final DBObject query,
final String field,
final Object value) {
final DBObject condition = new BasicDBObject();
condition.put(OP_NE, value);
query.put(field, condition);
return query;
}
public static DBObject queryNotEquals(final String field,
final Object value) {
final DBObject query = new BasicDBObject();
return queryNotEquals(query, field, value);
}
public static DBObject queryStartWith(final String field,
final String value) {
return queryStartWith(field, value, CASE_INSENSITIVE);
}
public static DBObject queryStartWith(final DBObject query,
final String field,
final String value) {
return queryStartWith(query, field, value, CASE_INSENSITIVE);
}
public static DBObject queryStartWith(final String field,
final String value,
final Integer flags) {
return queryStartWith(new BasicDBObject(), field, value, flags);
}
public static DBObject queryStartWith(final DBObject query,
final String field,
final String value,
final Integer flags) {
final Pattern pattern = patternStartWith(value, flags);
query.put(field, pattern);
return query;
}
public static DBObject queryIn(final String field,
final Object[] array) {
// { field : { $in : array } }
final DBObject in = new BasicDBObject(OP_IN, array);
return new BasicDBObject(field, in);
}
public static DBObject queryIn(final DBObject query,
final String field,
final Object[] array) {
// { field : { $in : array } }
final DBObject in = new BasicDBObject(OP_IN, array);
query.put(field, in);
return query;
}
/**
* Return a query object to search a value "like"
*
* @param field Search field
* @param value Search value
* @return
*/
public static DBObject queryContains(final String field,
final String value) {
// ^.*John.*$
return queryContains(field, value, CASE_INSENSITIVE);
}
/**
* @param field
* @param value
* @param flags Match flags, a bit mask.
* (i.e. Pattern.CASE_INSENSITIVE | Pattern.MULTILINE)
* @return
*/
public static DBObject queryContains(final String field,
final String value,
final Integer flags) {
// ^.*John.*$
final Pattern pattern = patternContains(value, flags);
final DBObject query = new BasicDBObject(field, pattern);
return query;
}
public static DBObject queryEndWith(final String field,
final String value) {
return queryEndWith(field, value, CASE_INSENSITIVE);
}
public static DBObject queryEndWith(final String field,
final String value, final Integer flags) {
final Pattern pattern = patternEndWith(value, flags);
final DBObject query = new BasicDBObject(field, pattern);
return query;
}
public static DBObject queryStartWithEndWith(final String field,
final String startValue, final String endValue) {
return queryStartWithEndWith(field, startValue, endValue, CASE_INSENSITIVE);
}
public static DBObject queryStartWithEndWith(final String field,
final String startValue, final String endValue, final Integer flags) {
final Pattern pattern = patternStartWithEndWith(startValue, endValue, flags);
final DBObject query = new BasicDBObject(field, pattern);
return query;
}
public static DBObject queryGreaterThan(final String field,
final Object value, final boolean equals) {
final DBObject condition = conditionGreaterThan(value, equals);
final DBObject query = new BasicDBObject(field, condition);
return query;
}
public static DBObject queryGreaterThan(final DBObject query,
final String field,
final Object value, final boolean equals) {
final DBObject condition = conditionGreaterThan(value, equals);
query.put(field, condition);
return query;
}
public static DBObject conditionGreaterThan(
final Object value, final boolean equals) {
final String operator = equals ? OP_GTE : OP_GT;
final DBObject condition = new BasicDBObject();
condition.put(operator, value);
return condition;
}
public static DBObject queryLowerThan(final String field,
final Object value, final boolean equals) {
final DBObject condition = conditionLowerThan(value, equals);
final DBObject query = new BasicDBObject(field, condition);
return query;
}
public static DBObject conditionLowerThan(
final Object value, final boolean equals) {
final String operator = equals ? OP_LTE : OP_LT;
final DBObject condition = new BasicDBObject();
condition.put(operator, value);
return condition;
}
public static DBObject queryBetween(final String field,
final Object value1, final Object value2, final boolean equals) {
final String op_lower = equals ? OP_LTE : OP_LT;
final String op_greater = equals ? OP_GTE : OP_GT;
final DBObject condition = new BasicDBObject();
condition.put(op_greater, value1);
condition.put(op_lower, value2);
final DBObject query = new BasicDBObject(field, condition);
return query;
}
public static DBObject queryFromTo(final String fieldFROM,
final String fieldTO, final Date date) {
final String today = FormatUtils.formatDate(date);
final DBObject from = new BasicDBObject();
from.put(IMongoConstants.OP_LTE, today);
final DBObject to = new BasicDBObject();
to.put(IMongoConstants.OP_GTE, today);
final DBObject query = new BasicDBObject();
query.put(fieldFROM, from);
query.put(fieldTO, to);
return query;
}
public static DBObject modifierSet(final String[] names,
final Object[] values) {
final DBObject modifier = new BasicDBObject();
if (!CollectionUtils.isEmpty(names) && !CollectionUtils.isEmpty(values)) {
final DBObject condition = new BasicDBObject();
for (int i = 0; i < names.length; i++) {
condition.put(names[i], values[i]);
}
modifier.put(MO_SET, condition);
}
return modifier;
}
/**
* { $addToSet : { field : value } }
*
* @param field
* @param value
* @return
*/
public static DBObject modifierAddToSet(final String field,
final Object value) {
final DBObject modifier = new BasicDBObject();
final DBObject condition = new BasicDBObject();
condition.put(field, value);
modifier.put(MO_ADDTOSET, condition);
return modifier;
}
/**
* { $pull : { field : {fieldName: value} } }
* Returns a pull modifier to
* remove all occurrences of value from field, if field is an array.
* If field is present but is not an array, an error condition is raised.
*
* @param fieldName Array field name
* @param names Condition field names
* @param values Condition field values
* @return { $pull : { field : {fieldName: value} } }
* i.e. removes array elements with fieldName matching value
*/
public static DBObject modifierPull(final String fieldName,
final String[] names, final Object[] values) {
final DBObject modifier = new BasicDBObject();
if (!CollectionUtils.isEmpty(names) && !CollectionUtils.isEmpty(values)) {
final DBObject condition = new BasicDBObject();
for (int i = 0; i < names.length; i++) {
condition.put(names[i], values[i]);
}
final DBObject field = new BasicDBObject(fieldName, condition);
modifier.put(MO_PULL, field);
}
return modifier;
}
/**
* { $pull : { field : _value } }
*
* @param fieldName
* @param value
* @return { $pull : { field : _value } }
*/
public static DBObject modifierPull(final String fieldName,
final Object value) {
final DBObject modifier = new BasicDBObject();
final DBObject condition = new BasicDBObject();
condition.put(fieldName, value);
modifier.put(MO_PULL, condition);
return modifier;
}
/**
* Remove empty array from List or simple DBObject.
* Empty Array are not valid in json and may cause parsing exceptions.
*
* @param object DBObject
* @return new instance of DBObject.
*/
public static DBObject removeEmptyArrays(final DBObject object) {
try {
if (object instanceof List) {
// BasicDBList
final List list = (List) object;
final BasicDBList result = new BasicDBList();
for (final Object obj : list) {
final Object cleaned;
if (obj instanceof DBObject) {
final DBObject item = (DBObject) obj;
cleaned = removeEmptyArrays(item);
} else {
cleaned = obj;
}
result.add(cleaned);
}
return result;
} else {
// BasicDBObject
final DBObject result = new BasicDBObject();
final Set<String> keys = object.keySet();
for (final String key : keys) {
final Object value = object.get(key.toString());
if (value instanceof List) {
final List list = (List) value;
if (!list.isEmpty()) {
if (list instanceof DBObject) {
result.put(key, removeEmptyArrays((DBObject) list));
} else {
result.put(key, list);
}
}
} else {
result.put(key, value);
}
}
return result;
}
} catch (Throwable t) {
LoggingUtils.getLogger().fine(t.toString());
}
return object;
}
/**
* Return an array of field names. i.e. {"_id", "name", ...} excluding from
* result all names in 'excludeFieldNames' parameter
*
* @param item The item to analyze for field names
* @param excludeFieldNames Names to exclude from list
* @return
*/
public static String[] getFieldNames(final DBObject item,
final String[] excludeFieldNames) {
final Set<String> keys = item.keySet();
if (CollectionUtils.isEmpty(excludeFieldNames)) {
return keys.toArray(new String[keys.size()]);
} else {
final List<String> result = new LinkedList<String>();
for (final String key : keys) {
if (!CollectionUtils.contains(excludeFieldNames, key)) {
result.add(key);
}
}
return result.toArray(new String[result.size()]);
}
}
/**
* Return an object containing fields to include or fields to exclude.
* i.e. "{thumbnail:0}" exclude 'thumbnail' field.
*
* @param fieldNames
* @param include
* @return
*/
public static DBObject getFields(final String[] fieldNames,
final boolean include) {
if (!CollectionUtils.isEmpty(fieldNames)) {
final DBObject result = new BasicDBObject();
for (final String field : fieldNames) {
result.put(field, include ? 1 : 0);
}
return result;
}
return null;
}
/**
* @param fieldNames
* @param ascending
* @return i.e. "{name : 1, age : 1}" 'name' and 'age'ascending<br/>
* i.e. "{name : -1, age : -1}" 'name' and 'age'descending
*/
public static DBObject getSortFields(final String[] fieldNames,
final boolean ascending) {
if (!CollectionUtils.isEmpty(fieldNames)) {
final DBObject result = new BasicDBObject();
for (final String field : fieldNames) {
result.put(field, ascending ? 1 : -1);
}
return result;
}
return new BasicDBObject(ID, 1);
}
/**
* @param asc
* @param desc
* @return i.e. "{name : 1, age : 1}" 'name' and 'age'ascending<br/>
* i.e. "{name : -1, age : -1}" 'name' and 'age'descending
*/
public static DBObject getSortFields(final String[] asc,
final String[] desc) {
if (!CollectionUtils.isEmpty(asc) || !CollectionUtils.isEmpty(desc)) {
final DBObject result = new BasicDBObject();
if (null != asc) {
for (final String field : asc) {
result.put(field, 1);
}
}
if (null != desc) {
for (final String field : desc) {
result.put(field, -1);
}
}
return result;
}
return new BasicDBObject(ID, 1);
}
/**
* Check two DBObject's ID. If item1._id==item2._id return true.
*
* @param item1
* @param item2
* @return
*/
public static boolean equals(final DBObject item1, final DBObject item2) {
final String id1 = MongoUtils.getIdAsString(item1);
final String id2 = MongoUtils.getIdAsString(item2);
return id1.equalsIgnoreCase(id2);
}
// ------------------------------------------------------------------------
// p r i v a t e
// ------------------------------------------------------------------------
private static void putValue(final DBObject target,
final String key,
final Collection sourcevalues,
final boolean overwrite) {
final Object tvalue = target.get(key);
if (tvalue instanceof Collection) {
final Collection tvaluelist = (Collection) tvalue;
// add items to target collection
CollectionUtils.addAllNoDuplicates(tvaluelist, sourcevalues);
} else {
// Source is Collection but target not.
if (overwrite || !target.containsField(key)) {
sourcevalues.add(tvalue);
target.put(key, sourcevalues);
}
}
}
private static void putValue(final DBObject target,
final String key,
final DBObject sourcevalue,
final boolean overwrite) {
final Object tvalue = target.get(key);
if (tvalue instanceof Collection) {
final Collection tvaluelist = (Collection) tvalue;
// TARGET is a Collection
CollectionUtils.addNoDuplicates(tvaluelist, sourcevalue);
} else if (tvalue instanceof DBObject) {
// TARGET is DBObject
// merge values
merge(sourcevalue, (DBObject) tvalue, null);
} else {
// TARGET is NULL or other Type (String, int, Object...)
if (overwrite || !target.containsField(key)) {
target.put(key, sourcevalue);
}
}
}
private static Object getDeepValue(final DBObject instance,
final String path)
throws IllegalAccessException, InvocationTargetException {
Object result = null;
if (StringUtils.hasText(path)) {
final String[] tokens = StringUtils.split(path, ".");
result = instance;
for (final String token : tokens) {
if (null != result) {
if (result instanceof BasicDBList) {
result = getPathValue((BasicDBList) result, token);
} else if (result instanceof BasicDBObject) {
result = ((BasicDBObject) result).get(token);
} else {
result = BeanUtils.getValueIfAny(result, token);
}
} else {
break;
}
}
}
return result;
}
private static Object getPathValue(final BasicDBList list,
final String idValue) {
for (final Object item : list) {
if (null != item && item instanceof DBObject) {
final DBObject dbitem = (DBObject) item;
for (final String fname : ID_FIELDS) {
final Object value = dbitem.get(fname);
if (CompareUtils.equals(value, idValue)) {
return item;
}
}
}
}
return null;
}
private static Object setPathValue(final DBObject instance,
final String path,
final Object value)
throws IllegalAccessException, InvocationTargetException {
Object result = null;
Object propertyBean = instance;
String fieldName = path;
if (StringUtils.hasText(path)) {
final String[] tokens = StringUtils.split(path, ".");
if (tokens.length > 1) {
final String[] a = CollectionUtils.removeTokenFromArray(tokens, tokens.length - 1);
final String new_path = CollectionUtils.toDelimitedString(a, ".");
propertyBean = getDeepValue(instance, new_path);
fieldName = CollectionUtils.getLast(tokens);
}
}
if (null != propertyBean) {
if (propertyBean instanceof DBObject) {
result = ((DBObject) propertyBean).get(fieldName);
((DBObject) propertyBean).put(fieldName, value);
} else {
result = BeanUtils.getValueIfAny(propertyBean, fieldName);
BeanUtils.setValueIfAny(propertyBean, fieldName, value);
}
}
return result;
}
}