PageRenderTime 23ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/core/infinit.e.data_model/src/com/ikanow/infinit/e/data_model/store/MongoDbUtil.java

https://github.com/IKANOW/Infinit.e
Java | 320 lines | 283 code | 16 blank | 21 comment | 89 complexity | 1ee9f70bc139723f10bcdb87d7b10579 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /*******************************************************************************
  2. * Copyright 2012 The Infinit.e Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. ******************************************************************************/
  16. package com.ikanow.infinit.e.data_model.store;
  17. import java.text.ParseException;
  18. import java.util.Collection;
  19. import java.util.Date;
  20. import java.util.Iterator;
  21. import java.util.List;
  22. import java.util.Map;
  23. import org.bson.BSONObject;
  24. import org.bson.BasicBSONObject;
  25. import org.bson.types.BasicBSONList;
  26. import org.bson.types.ObjectId;
  27. import com.google.gson.JsonArray;
  28. import com.google.gson.JsonElement;
  29. import com.google.gson.JsonObject;
  30. import com.google.gson.JsonPrimitive;
  31. import com.ikanow.infinit.e.data_model.utils.ThreadSafeSimpleDateFormat;
  32. import com.mongodb.BasicDBList;
  33. import com.mongodb.BasicDBObject;
  34. import com.mongodb.DBCursor;
  35. import com.mongodb.DBObject;
  36. import com.mongodb.hadoop.io.BSONWritable;
  37. public class MongoDbUtil {
  38. @SuppressWarnings({ "unchecked", "rawtypes" })
  39. public static <T> T getProperty(DBObject dbo, String fieldInDotNotation) {
  40. final String[] keys = fieldInDotNotation.split( "\\." );
  41. DBObject current = dbo;
  42. Object result = null;
  43. for ( int i = 0; i < keys.length; i++ ) {
  44. result = current.get( keys[i] );
  45. if (null == result) {
  46. return null;
  47. }
  48. if (result instanceof Collection) {
  49. result = ((Collection)result).iterator().next();
  50. }
  51. else if (result instanceof Object[]) {
  52. result = ((Object[])result)[0];
  53. }
  54. if ( i + 1 < keys.length ) {
  55. if (current instanceof DBObject) {
  56. current = (DBObject) result;
  57. }
  58. else {
  59. return null;
  60. }
  61. }
  62. }
  63. return (T) result;
  64. }//TESTED
  65. public static void removeProperty(BasicDBObject dbo, String fieldInDotNotation) {
  66. final String[] keys = fieldInDotNotation.split( "\\." );
  67. recursiveNestedMapDelete(keys, 0, dbo);
  68. }//TESTED
  69. public static JsonElement encode(DBCursor cursor) {
  70. JsonArray result = new JsonArray();
  71. while (cursor.hasNext()) {
  72. DBObject dbo = cursor.next();
  73. result.add(encode(dbo));
  74. }
  75. return result;
  76. }//TESTED
  77. public static JsonElement encode(List<DBObject> listOfObjects) {
  78. JsonArray result = new JsonArray();
  79. for (DBObject dbo: listOfObjects) {
  80. result.add(encode(dbo));
  81. }
  82. return result;
  83. }//TESTED
  84. public static JsonElement encode(BasicBSONList a) {
  85. JsonArray result = new JsonArray();
  86. for (int i = 0; i < a.size(); ++i) {
  87. Object o = a.get(i);
  88. if (o instanceof DBObject) {
  89. result.add(encode((DBObject)o));
  90. }
  91. else if (o instanceof BasicBSONObject) {
  92. result.add(encode((BasicBSONObject)o));
  93. }
  94. else if (o instanceof BasicBSONList) {
  95. result.add(encode((BasicBSONList)o));
  96. }
  97. else if (o instanceof BasicDBList) {
  98. result.add(encode((BasicDBList)o));
  99. }
  100. else { // Must be a primitive...
  101. if (o instanceof String) {
  102. result.add(new JsonPrimitive((String)o));
  103. }
  104. else if (o instanceof Number) {
  105. result.add(new JsonPrimitive((Number)o));
  106. }
  107. else if (o instanceof Boolean) {
  108. result.add(new JsonPrimitive((Boolean)o));
  109. }
  110. // MongoDB special fields
  111. else if (o instanceof ObjectId) {
  112. JsonObject oid = new JsonObject();
  113. oid.add("$oid", new JsonPrimitive(((ObjectId)o).toString()));
  114. result.add(oid);
  115. }
  116. else if (o instanceof Date) {
  117. JsonObject date = new JsonObject();
  118. date.add("$date", new JsonPrimitive(_format.format((Date)o)));
  119. result.add(date);
  120. }
  121. // Ignore BinaryData, should be serializing that anyway...
  122. }
  123. }
  124. return result;
  125. }//TESTED
  126. public static JsonElement encode(BSONObject o) {
  127. JsonObject result = new JsonObject();
  128. Iterator<?> i = o.keySet().iterator();
  129. while (i.hasNext()) {
  130. String k = (String)i.next();
  131. Object v = o.get(k);
  132. if (v instanceof BasicBSONList) {
  133. result.add(k, encode((BasicBSONList)v));
  134. }
  135. else if (v instanceof BasicDBList) {
  136. result.add(k, encode((BasicDBList)v));
  137. }
  138. else if (v instanceof DBObject) {
  139. result.add(k, encode((DBObject)v));
  140. }
  141. else if (v instanceof BasicBSONObject) {
  142. result.add(k, encode((BasicBSONObject)v));
  143. }
  144. else { // Must be a primitive...
  145. if (v instanceof String) {
  146. result.add(k, new JsonPrimitive((String)v));
  147. }
  148. else if (v instanceof Number) {
  149. result.add(k, new JsonPrimitive((Number)v));
  150. }
  151. else if (v instanceof Boolean) {
  152. result.add(k, new JsonPrimitive((Boolean)v));
  153. }
  154. // MongoDB special fields
  155. else if (v instanceof ObjectId) {
  156. JsonObject oid = new JsonObject();
  157. oid.add("$oid", new JsonPrimitive(((ObjectId)v).toString()));
  158. result.add(k, oid);
  159. }
  160. else if (v instanceof Date) {
  161. JsonObject date = new JsonObject();
  162. date.add("$date", new JsonPrimitive(_format.format((Date)v)));
  163. result.add(k, date);
  164. }
  165. // Ignore BinaryData, should be serializing that anyway...
  166. }
  167. }
  168. return result;
  169. }//TESTED
  170. private static ThreadSafeSimpleDateFormat _format = new ThreadSafeSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
  171. private static ThreadSafeSimpleDateFormat _format2 = new ThreadSafeSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S'Z'");
  172. public static Object encodeUnknown(JsonElement from) {
  173. if (from.isJsonArray()) { // Array
  174. return encodeArray(from.getAsJsonArray());
  175. }//TESTED
  176. else if (from.isJsonObject()) { // Object
  177. JsonObject obj = from.getAsJsonObject();
  178. // Check for OID/Date:
  179. if (1 == obj.entrySet().size()) {
  180. if (obj.has("$date")) {
  181. try {
  182. return _format.parse(obj.get("$date").getAsString());
  183. } catch (ParseException e) {
  184. try {
  185. return _format2.parse(obj.get("$date").getAsString());
  186. } catch (ParseException e2) {
  187. return null;
  188. }
  189. }
  190. }//TESTED
  191. else if (obj.has("$oid")) {
  192. return new ObjectId(obj.get("$oid").getAsString());
  193. }//TESTED
  194. }
  195. return encode(obj);
  196. }//TESTED
  197. else if (from.isJsonPrimitive()) { // Primitive
  198. JsonPrimitive val = from.getAsJsonPrimitive();
  199. if (val.isNumber()) {
  200. return val.getAsNumber();
  201. }//TESTED
  202. else if (val.isBoolean()) {
  203. return val.getAsBoolean();
  204. }//TESTED
  205. else if (val.isString()) {
  206. return val.getAsString();
  207. }//TESTED
  208. }//TESTED
  209. return null;
  210. }//TESTED
  211. public static BasicDBList encodeArray(JsonArray a) {
  212. BasicDBList dbl = new BasicDBList();
  213. for (JsonElement el: a) {
  214. dbl.add(encodeUnknown(el));
  215. }
  216. return dbl;
  217. }//TESTED
  218. public static BasicDBObject encode(JsonObject o) {
  219. BasicDBObject dbo = new BasicDBObject();
  220. for (Map.Entry<String, JsonElement> elKV: o.entrySet()) {
  221. dbo.append(elKV.getKey(), encodeUnknown(elKV.getValue()));
  222. }
  223. return dbo;
  224. }//TESTED
  225. public static DBObject convert(BSONWritable dbo) {
  226. DBObject out = new BasicDBObject();
  227. for (Object entryIt: dbo.toMap().entrySet()) {
  228. @SuppressWarnings("unchecked")
  229. Map.Entry<String, Object> entry = (Map.Entry<String, Object>)entryIt;
  230. out.put(entry.getKey(), entry.getValue());
  231. }
  232. return out;
  233. }//TESTED
  234. public static BSONWritable convert(BSONObject dbo) {
  235. BSONWritable out = new BSONWritable();
  236. for (Object entryIt: dbo.toMap().entrySet()) {
  237. @SuppressWarnings("unchecked")
  238. Map.Entry<String, Object> entry = (Map.Entry<String, Object>)entryIt;
  239. out.put(entry.getKey(), entry.getValue());
  240. }
  241. return out;
  242. }//TESTED
  243. // UTILS:
  244. @SuppressWarnings("rawtypes")
  245. public static void recursiveNestedMapDelete(String[] fieldList, int currPos, Map currMap) {
  246. String metaFieldEl = fieldList[currPos];
  247. if (currPos == (fieldList.length - 1)) {
  248. currMap.remove(metaFieldEl);
  249. }//TESTED (metadataStorage_test:removeString, etc)
  250. else {
  251. Object metaFieldElValOrVals = currMap.get(metaFieldEl);
  252. if (null != metaFieldElValOrVals) {
  253. if (metaFieldElValOrVals instanceof Map) {
  254. Map map = (Map)metaFieldElValOrVals;
  255. recursiveNestedMapDelete(fieldList, currPos + 1, map);
  256. if (map.isEmpty()) {
  257. currMap.remove(metaFieldEl);
  258. }//TESTED (metadataStorage_test:object)
  259. }//TESTED (metadataStorage_test:object, :nestedArrayOfStrings, etc)
  260. else if (metaFieldElValOrVals instanceof Object[]) {
  261. Object[] candidateMaps = (Object[])metaFieldElValOrVals;
  262. boolean allEmpty = (candidateMaps.length > 0);
  263. for (Object candidateMap: candidateMaps) {
  264. if (candidateMap instanceof Map) {
  265. Map map = (Map)candidateMap;
  266. recursiveNestedMapDelete(fieldList, currPos + 1, map);
  267. allEmpty &= map.isEmpty();
  268. }
  269. else allEmpty = false;
  270. }
  271. if (allEmpty) {
  272. currMap.remove(metaFieldEl);
  273. }//TESTED (metadataStorage_test:test2,test3)
  274. }//TESTED (length 1: metadataStorage_test:removeString, etc; length2: :test2,test3)
  275. else if (metaFieldElValOrVals instanceof Map[]) {
  276. Map[] maps = (Map[])metaFieldElValOrVals;
  277. boolean allEmpty = (maps.length > 0);
  278. for (Map map: maps) {
  279. recursiveNestedMapDelete(fieldList, currPos + 1, map);
  280. allEmpty &= map.isEmpty();
  281. }
  282. if (allEmpty) {
  283. currMap.remove(metaFieldEl);
  284. }
  285. }//(basically the same as the clause above, doesn't seem to occur in practice)
  286. else if (metaFieldElValOrVals instanceof Collection) {
  287. Collection candidateMaps = (Collection)metaFieldElValOrVals;
  288. boolean allEmpty = (candidateMaps.size() > 0);
  289. for (Object candidateMap: candidateMaps) {
  290. if (candidateMap instanceof Map) {
  291. Map map = (Map)candidateMap;
  292. recursiveNestedMapDelete(fieldList, currPos + 1, map);
  293. allEmpty &= map.isEmpty();
  294. }
  295. else allEmpty = false;
  296. }
  297. if (allEmpty) {
  298. currMap.remove(metaFieldEl);
  299. }//TESTED (metadataStorage_test:nestedMapArray, metadataStorage_test:nestedMapArray2, metadataStorage_test:nestedMixedArray)
  300. }//TESTED (length>1: metadataStorage_test:nestedMixedArray,nestedMapArray)
  301. }
  302. }//(end if at the start/middle of the nested object tree)
  303. }//TESTED
  304. }