/src/main/java/com/springsource/insight/plugin/mongodb/MongoArgumentUtils.java

https://github.com/spring-projects/insight-plugin-mongodb · Java · 204 lines · 109 code · 28 blank · 67 comment · 9 complexity · ee5a94eb3905666e40bab2a6a7511622 MD5 · raw file

  1. package com.springsource.insight.plugin.mongodb;
  2. import java.math.BigDecimal;
  3. import java.math.BigInteger;
  4. import java.util.ArrayList;
  5. import java.util.HashMap;
  6. import java.util.List;
  7. import java.util.Map;
  8. import org.bson.types.ObjectId;
  9. import com.mongodb.BasicDBList;
  10. import com.mongodb.BasicDBObject;
  11. import com.mongodb.CommandResult;
  12. import com.mongodb.DBCollection;
  13. import com.mongodb.DBCursor;
  14. import com.mongodb.DBObject;
  15. import com.mongodb.WriteConcern;
  16. import com.mongodb.WriteResult;
  17. /**
  18. * Utilities for converting method arguments for MongoDB-related operations
  19. */
  20. public class MongoArgumentUtils {
  21. /**
  22. * The maximum length of a string we generate
  23. */
  24. private static final int MAX_STRING_LENGTH = 256;
  25. private static final String ELLIPSIS = "...";
  26. /**
  27. * These classes can just be converted willy-nilly
  28. */
  29. private static final Class<?>[] SIMPLE_CLASSES = new Class<?>[]{
  30. String.class, Boolean.class, Byte.class, Character.class,
  31. Short.class, Integer.class, Long.class, Float.class, Double.class,
  32. BigInteger.class, BigDecimal.class};
  33. /**
  34. * With care, we can treat these MongoDB classes simply too
  35. */
  36. private static final Class<?>[] SIMPLE_MONGO_CLASSES = new Class<?>[]{
  37. ObjectId.class, CommandResult.class, BasicDBList.class,
  38. BasicDBObject.class, DBCollection.class, WriteConcern.class,
  39. WriteResult.class};
  40. /**
  41. * A little helper interface to convert an {@link Object} to a
  42. * {@link String}
  43. *
  44. * @param <T>
  45. */
  46. private interface StringForm<T extends Object> {
  47. /**
  48. * @param object guaranteed non-null
  49. * @return
  50. */
  51. String stringify(T object);
  52. }
  53. /**
  54. * Take an object from one of the "safe" classes, convert to a
  55. * {@link String} and trim the result, perhaps using ellipses if we truncate
  56. * it
  57. */
  58. private static final StringForm<Object> DefaultStringForm = new StringForm<Object>() {
  59. public String stringify(final Object object) {
  60. return object.toString();
  61. }
  62. };
  63. /**
  64. * For a {@link DBCursor}, we get the {@link DBCollection} name, the query
  65. * and the keys wanted
  66. */
  67. private static final StringForm<DBCursor> DBCursorStringForm = new StringForm<DBCursor>() {
  68. public String stringify(final DBCursor cursor) {
  69. return "DBCursor(" + MongoArgumentUtils.toString(cursor.getQuery()) + ", "
  70. + MongoArgumentUtils.toString(cursor.getKeysWanted()) + ")";
  71. }
  72. };
  73. /**
  74. * This type is common for inserts. In fact, even a single insert gets
  75. * converted to a {@link DBObject}[]
  76. */
  77. private static final StringForm<DBObject[]> DBObjectArrayStringForm = new StringForm<DBObject[]>() {
  78. public String stringify(final DBObject[] array) {
  79. return "DBObject" + MongoArgumentUtils.toString(array);
  80. }
  81. };
  82. /**
  83. * A map from a {@link Class} to a helper ({@link StringForm}) that returns
  84. * a suitable {@link String} value
  85. * <p/>
  86. * You'll get used to this style of object creation if you stare at it long
  87. * enough. It's handy because you don't need to mention the name of the
  88. * variable (STRING_FORM_MAP) in any of the put() calls, which you'd have to
  89. * if you did it long hand.
  90. */
  91. private static final Map<Class<?>, StringForm<? extends Object>> STRING_FORM_MAP = new HashMap<Class<?>, StringForm<? extends Object>>() {
  92. {
  93. // Wrapper classes
  94. //
  95. for (Class<?> cls : SIMPLE_CLASSES) {
  96. put(cls, DefaultStringForm);
  97. }
  98. // MongoDB classes
  99. //
  100. for (Class<?> cls : SIMPLE_MONGO_CLASSES) {
  101. put(cls, DefaultStringForm);
  102. }
  103. put(DBCursor.class, DBCursorStringForm);
  104. put(DBObject[].class, DBObjectArrayStringForm);
  105. }
  106. };
  107. private MongoArgumentUtils() {
  108. // empty OK
  109. }
  110. public static List<String> toString(final Object[] array) {
  111. return toString(array, MAX_STRING_LENGTH);
  112. }
  113. /**
  114. * Convert an {@link Object}[] to a {@link String}. Don't convert more than
  115. * MAX_ARGS arguments and don't make it more than roughly maxLength long.
  116. * <p/>
  117. * Append ellipses to any argument we truncate, or to the whole array if
  118. * it's too long.
  119. *
  120. * @param array
  121. * @param maxLength
  122. * @return
  123. */
  124. public static List<String> toString(final Object[] array,
  125. final int maxLength) {
  126. return new ArrayList<String>() {
  127. {
  128. int soFar = 0;
  129. for (final Object arg : array) {
  130. final String result
  131. = MongoArgumentUtils.toString(arg, maxLength - soFar);
  132. soFar += result.length();
  133. add(result);
  134. if (soFar >= maxLength) {
  135. break;
  136. }
  137. }
  138. }
  139. };
  140. }
  141. public static String toString(final Object object) {
  142. return toString(object, MAX_STRING_LENGTH);
  143. }
  144. /**
  145. * Primitives and "safe" types get a call to {@link #toString()} via the
  146. * {@link StringForm} helper class; everything else is just the class name.
  147. *
  148. * @param object
  149. * @return
  150. */
  151. @SuppressWarnings("unchecked")
  152. public static String toString(final Object object, final int maxLength) {
  153. if (object == null) {
  154. return "null";
  155. }
  156. Class<? extends Object> cls = object.getClass();
  157. StringForm<Object> stringForm = (StringForm<Object>) STRING_FORM_MAP
  158. .get(cls);
  159. if (stringForm != null) {
  160. return trimWithEllipsis(stringForm.stringify(object), maxLength);
  161. }
  162. return cls.getSimpleName();
  163. }
  164. private static String toString(final DBObject dbObject) {
  165. return dbObject == null ? null : trimWithEllipsis(dbObject.toString());
  166. }
  167. private static String trimWithEllipsis(final String string) {
  168. return trimWithEllipsis(string, MAX_STRING_LENGTH);
  169. }
  170. private static String trimWithEllipsis(final String string,
  171. final int maxLength) {
  172. return string.length() <= maxLength + ELLIPSIS.length()
  173. ? string
  174. : string.substring(0, maxLength) + ELLIPSIS;
  175. }
  176. }