PageRenderTime 81ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/src/net/ion/repository/mongo/Fqn.java

https://github.com/bleujin/mongoNode
Java | 368 lines | 295 code | 65 blank | 8 comment | 75 complexity | ff08fc54fc28b3b159b249001347f2c3 MD5 | raw file
  1. package net.ion.repository.mongo;
  2. import java.io.Serializable;
  3. import java.util.Arrays;
  4. import java.util.Comparator;
  5. import java.util.List;
  6. import java.util.Map;
  7. import net.ion.framework.parse.gson.JsonPrimitive;
  8. import net.ion.framework.util.MapUtil;
  9. import net.ion.framework.util.ObjectUtil;
  10. import net.ion.repository.mongo.uriparser.URIPattern;
  11. import net.ion.repository.mongo.uriparser.URIResolveResult;
  12. import net.ion.repository.mongo.uriparser.URIResolver;
  13. import com.google.common.base.Splitter;
  14. import com.google.common.collect.Iterables;
  15. import com.mongodb.BasicDBObject;
  16. import com.mongodb.DBObject;
  17. public class Fqn implements Comparable<Fqn>, Serializable {
  18. private static final long serialVersionUID = -2662673757638992543L;
  19. public static final String SEPARATOR = "/";
  20. private final String[] elements;
  21. private transient int hash_code = 0;
  22. public static final Fqn ROOT = new Fqn();
  23. public static final Fqn TRANSACTIONS = Fqn.fromString("/__transactions");
  24. protected String stringRepresentation;
  25. private static final String[] EMPTY_ARRAY = new String[0];
  26. private Fqn(String... elements) {
  27. this.elements = elements;
  28. }
  29. private Fqn(List<String> names) {
  30. elements = (names != null) ? names.toArray(new String[0]) : EMPTY_ARRAY;
  31. }
  32. private Fqn(Fqn base, Object... relative) {
  33. elements = new String[base.elements.length + relative.length];
  34. System.arraycopy(base.elements, 0, elements, 0, base.elements.length);
  35. System.arraycopy(relative, 0, elements, base.elements.length, relative.length);
  36. }
  37. @SuppressWarnings("unchecked")
  38. public static Fqn fromList(List<String> names) {
  39. return new Fqn(names);
  40. }
  41. public static Fqn fromElements(String... elements) {
  42. String[] copy = new String[elements.length];
  43. System.arraycopy(elements, 0, copy, 0, elements.length);
  44. return new Fqn(copy);
  45. }
  46. public static Fqn fromRelativeFqn(Fqn base, Fqn relative) {
  47. return new Fqn(base, relative.elements);
  48. }
  49. public static Fqn fromRelativeList(Fqn base, List<?> relativeElements) {
  50. return new Fqn(base, relativeElements.toArray());
  51. }
  52. public static Fqn fromRelativeElements(Fqn base, Object... relativeElements) {
  53. return new Fqn(base, relativeElements);
  54. }
  55. public static Fqn fromString(String stringRepresentation) {
  56. if (stringRepresentation == null || stringRepresentation.equals(SEPARATOR) || stringRepresentation.length() == 0)
  57. return root();
  58. String toMatch = stringRepresentation.startsWith(SEPARATOR) ? stringRepresentation.substring(1) : stringRepresentation;
  59. String[] el = toMatch.split(SEPARATOR);
  60. // return new Fqn(el) ;
  61. return new Fqn(Iterables.toArray(Splitter.on(SEPARATOR).trimResults().omitEmptyStrings().split(toMatch), String.class));
  62. }
  63. public Fqn relativeFqn(String childFqn){
  64. return Fqn.fromRelativeFqn(this, Fqn.fromString(childFqn)) ;
  65. }
  66. public Fqn getAncestor(int generation) {
  67. if (generation == 0)
  68. return root();
  69. return getSubFqn(0, generation);
  70. }
  71. public Fqn getSubFqn(int startIndex, int endIndex) {
  72. if (endIndex < startIndex)
  73. throw new IllegalArgumentException("End index cannot be less than the start index!");
  74. int len = endIndex - startIndex;
  75. String[] el = new String[len];
  76. System.arraycopy(elements, startIndex, el, 0, len);
  77. return new Fqn(el);
  78. }
  79. public int size() {
  80. return elements.length;
  81. }
  82. public Object get(int n) {
  83. return elements[n];
  84. }
  85. public JsonPrimitive toJson() {
  86. return new JsonPrimitive(toString());
  87. }
  88. public Object getLastElement() {
  89. if (isRoot())
  90. return null;
  91. return elements[elements.length - 1];
  92. }
  93. public boolean hasElement(Object element) {
  94. return indexOf(element) != -1;
  95. }
  96. private int indexOf(Object element) {
  97. if (element == null) {
  98. for (int i = 0; i < elements.length; i++) {
  99. if (elements[i] == null)
  100. return i;
  101. }
  102. } else {
  103. for (int i = 0; i < elements.length; i++) {
  104. if (element.equals(elements[i]))
  105. return i;
  106. }
  107. }
  108. return -1;
  109. }
  110. @Override
  111. public boolean equals(Object obj) {
  112. if (this == obj) {
  113. return true;
  114. }
  115. if (!(obj instanceof Fqn)) {
  116. return false;
  117. }
  118. Fqn other = (Fqn) obj;
  119. if (elements.length != other.elements.length)
  120. return false;
  121. for (int i = elements.length - 1; i >= 0; i--) {
  122. if (!safeEquals(elements[i], other.elements[i]))
  123. return false;
  124. }
  125. return true;
  126. }
  127. @Override
  128. public int hashCode() {
  129. if (hash_code == 0) {
  130. hash_code = calculateHashCode();
  131. }
  132. return hash_code;
  133. }
  134. @Override
  135. public String toString() {
  136. if (stringRepresentation == null) {
  137. stringRepresentation = getStringRepresentation(elements);
  138. }
  139. return stringRepresentation;
  140. }
  141. public boolean isChildOf(Fqn parentFqn) {
  142. return parentFqn.elements.length != elements.length && isChildOrEquals(parentFqn);
  143. }
  144. public boolean isDirectChildOf(Fqn parentFqn) {
  145. return elements.length == parentFqn.elements.length + 1 && isChildOf(parentFqn);
  146. }
  147. public boolean isChildOrEquals(Fqn parentFqn) {
  148. Object[] parentEl = parentFqn.elements;
  149. if (parentEl.length > elements.length) {
  150. return false;
  151. }
  152. for (int i = parentEl.length - 1; i >= 0; i--) {
  153. if (!safeEquals(parentEl[i], elements[i]))
  154. return false;
  155. }
  156. return true;
  157. }
  158. protected int calculateHashCode() {
  159. int hashCode = 19;
  160. for (Object o : elements)
  161. hashCode = 31 * hashCode + (o == null ? 0 : o.hashCode());
  162. if (hashCode == 0)
  163. hashCode = 0xDEADBEEF; // degenerate case
  164. return hashCode;
  165. }
  166. protected String getStringRepresentation(Object[] elements) {
  167. StringBuilder builder = new StringBuilder();
  168. for (Object e : elements) {
  169. // incase user element 'e' does not implement equals() properly, don't rely on their implementation.
  170. if (!SEPARATOR.equals(e) && !"".equals(e)) {
  171. builder.append(SEPARATOR);
  172. builder.append(e);
  173. }
  174. }
  175. return builder.length() == 0 ? SEPARATOR : builder.toString();
  176. }
  177. public Fqn getParent() {
  178. switch (elements.length) {
  179. case 0:
  180. case 1:
  181. return root();
  182. default:
  183. return getSubFqn(0, elements.length - 1);
  184. }
  185. }
  186. public static Fqn root() { // declared final so compilers can optimise and in-line.
  187. return ROOT;
  188. }
  189. public boolean isRoot() {
  190. return elements.length == 0;
  191. }
  192. public String getLastElementAsString() {
  193. if (isRoot()) {
  194. return SEPARATOR;
  195. } else {
  196. Object last = getLastElement();
  197. if (last instanceof String)
  198. return (String) last;
  199. else
  200. return String.valueOf(getLastElement());
  201. }
  202. }
  203. public List<String> peekElements() {
  204. return Arrays.asList(elements);
  205. }
  206. @Override
  207. public int compareTo(Fqn fqn) {
  208. return FqnComparator.INSTANCE.compare(this, fqn);
  209. }
  210. public Fqn replaceAncestor(Fqn oldAncestor, Fqn newAncestor) {
  211. if (!isChildOf(oldAncestor))
  212. throw new IllegalArgumentException("Old ancestor must be an ancestor of the current Fqn!");
  213. Fqn subFqn = this.getSubFqn(oldAncestor.size(), size());
  214. return Fqn.fromRelativeFqn(newAncestor, subFqn);
  215. }
  216. public String name() {
  217. return ObjectUtil.toString(getLastElement());
  218. }
  219. public String startWith() {
  220. return isRoot() ? "/*" : toString() + "/*";
  221. }
  222. private static boolean safeEquals(Object a, Object b) {
  223. return a == b || a != null && a.equals(b);
  224. }
  225. public BasicDBObject idQueryObject() {
  226. BasicDBObject result = new BasicDBObject("_id", toString()) ;
  227. result.put("_parent", getParent().toString()) ;
  228. return result ;
  229. }
  230. public DBObject parentQueryObject() {
  231. return new BasicDBObject("_parent", getParent().toString()) ;
  232. }
  233. public DBObject childrenQueryObject() {
  234. return new BasicDBObject("_id", new BasicDBObject("$gt", isRoot() ? "/" : (toString() + "/"))) ;
  235. }
  236. public static Fqn fromDBObject(DBObject dbo) {
  237. return Fqn.fromString(dbo.get("_id").toString());
  238. }
  239. public int depth() {
  240. return elements.length;
  241. }
  242. public boolean isPattern(String fqnPattern) {
  243. return new URIPattern(fqnPattern).match(this.toString());
  244. }
  245. public Map<String, String> resolve(String fqnPattern){
  246. URIResolveResult resolver = new URIResolver(toString()).resolve(new URIPattern(fqnPattern));
  247. Map<String, String> result = MapUtil.newMap() ;
  248. for(String name : resolver.names()){
  249. result.put(name, ObjectUtil.toString(resolver.get(name))) ;
  250. }
  251. return result ;
  252. }
  253. }
  254. class FqnComparator implements Comparator<Fqn>, Serializable {
  255. public static final FqnComparator INSTANCE = new FqnComparator();
  256. private static final long serialVersionUID = -1357631755443829281L;
  257. /**
  258. * Returns -1 if the first comes before; 0 if they are the same; 1 if the second Fqn comes before. <code>null</code> always comes first.
  259. */
  260. @Override
  261. public int compare(Fqn fqn1, Fqn fqn2) {
  262. int s1 = fqn1.size();
  263. int s2 = fqn2.size();
  264. if (s1 == 0) {
  265. return (s2 == 0) ? 0 : -1;
  266. }
  267. if (s2 == 0) {
  268. return 1;
  269. }
  270. int size = Math.min(s1, s2);
  271. for (int i = 0; i < size; i++) {
  272. Object e1 = fqn1.get(i);
  273. Object e2 = fqn2.get(i);
  274. if (e1 == e2) {
  275. continue;
  276. }
  277. if (e1 == null) {
  278. return 0;
  279. }
  280. if (e2 == null) {
  281. return 1;
  282. }
  283. if (!e1.equals(e2)) {
  284. int c = compareElements(e1, e2);
  285. if (c != 0) {
  286. return c;
  287. }
  288. }
  289. }
  290. return s1 - s2;
  291. }
  292. /**
  293. * Compares two Fqn elements. If e1 and e2 are the same class and e1 implements Comparable, returns e1.compareTo(e2). Otherwise, returns e1.toString().compareTo(e2.toString()).
  294. */
  295. @SuppressWarnings("unchecked")
  296. private int compareElements(Object e1, Object e2) {
  297. if (e1.getClass() == e2.getClass() && e1 instanceof Comparable) {
  298. return ((Comparable<Object>) e1).compareTo(e2);
  299. } else {
  300. return e1.toString().compareTo(e2.toString());
  301. }
  302. }
  303. }