PageRenderTime 42ms CodeModel.GetById 4ms RepoModel.GetById 1ms app.codeStats 0ms

/streams-confluence-plugin/src/main/java/com/atlassian/streams/confluence/ConfluenceSearchQueryBuilder.java

https://bitbucket.org/atlassianlabs/jira-fisheye-streams-integration
Java | 283 lines | 242 code | 40 blank | 1 comment | 20 complexity | 065da436326ca21d4e6668aa22c83b24 MD5 | raw file
  1. package com.atlassian.streams.confluence;
  2. import com.atlassian.confluence.search.service.ContentTypeEnum;
  3. import com.atlassian.confluence.search.v2.SearchQuery;
  4. import com.atlassian.confluence.search.v2.query.*;
  5. import static com.atlassian.streams.util.Preconditions.*;
  6. import static org.apache.commons.collections.CollectionUtils.*;
  7. import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
  8. import org.apache.commons.collections.Transformer;
  9. import org.apache.commons.collections.functors.NotNullPredicate;
  10. import static org.apache.commons.lang.StringUtils.*;
  11. import java.util.*;
  12. public class ConfluenceSearchQueryBuilder
  13. {
  14. // names of the text fields used by Confluence internally, will break if any is renamed by Confluence
  15. private static final String[] TEXT_FIELDS =
  16. {"title", "labelText", "contentBody", "filename", "username", "fullName", "email", "from", "recipients"};
  17. private final Set<String> createdByUsers = new LinkedHashSet<String>();
  18. private final Set<String> lastModifiedByUsers = new LinkedHashSet<String>();
  19. private final Set<String> spaceKeys = new LinkedHashSet<String>();
  20. private final Set<String> searchTerms = new LinkedHashSet<String>();
  21. private final Set<ContentTypeEnum> contentTypes = new LinkedHashSet<ContentTypeEnum>();
  22. public ConfluenceSearchQueryBuilder createdOrLastModifiedBy(Collection<String> userNames)
  23. {
  24. return createdBy(userNames).lastModifiedBy(userNames);
  25. }
  26. public ConfluenceSearchQueryBuilder createdOrLastModifiedBy(String... userNames)
  27. {
  28. return createdOrLastModifiedBy(nullSafeCollection(userNames));
  29. }
  30. @SuppressWarnings("unchecked")
  31. public ConfluenceSearchQueryBuilder createdBy(Collection<String> userNames)
  32. {
  33. createdByUsers.addAll(collect(nullSafeCollection(userNames), StringTrimmer.INSTANCE));
  34. return this;
  35. }
  36. public ConfluenceSearchQueryBuilder createdBy(String... userNames)
  37. {
  38. return createdBy(nullSafeCollection(userNames));
  39. }
  40. @SuppressWarnings("unchecked")
  41. public ConfluenceSearchQueryBuilder lastModifiedBy(Collection<String> userNames)
  42. {
  43. lastModifiedByUsers.addAll(collect(nullSafeCollection(userNames), StringTrimmer.INSTANCE));
  44. return this;
  45. }
  46. public ConfluenceSearchQueryBuilder lastModifiedBy(String... userNames)
  47. {
  48. return lastModifiedBy(nullSafeCollection(userNames));
  49. }
  50. @SuppressWarnings("unchecked")
  51. public ConfluenceSearchQueryBuilder inSpace(Collection<String> spaceKeys)
  52. {
  53. this.spaceKeys.addAll(collect(nullSafeCollection(spaceKeys), StringTrimmer.INSTANCE));
  54. return this;
  55. }
  56. public ConfluenceSearchQueryBuilder inSpace(String... spaceKeys)
  57. {
  58. return inSpace(nullSafeCollection(spaceKeys));
  59. }
  60. @SuppressWarnings("unchecked")
  61. public ConfluenceSearchQueryBuilder searchFor(Collection<String> searchTerms)
  62. {
  63. this.searchTerms.addAll(collect(nullSafeCollection(searchTerms), StringTrimmer.INSTANCE));
  64. return this;
  65. }
  66. public ConfluenceSearchQueryBuilder searchFor(String... searchTerms)
  67. {
  68. return searchFor(nullSafeCollection(searchTerms));
  69. }
  70. public ConfluenceSearchQueryBuilder contentType(Collection<ContentTypeEnum> types)
  71. {
  72. this.contentTypes.addAll(nullSafeCollection(types));
  73. return this;
  74. }
  75. public ConfluenceSearchQueryBuilder contentType(ContentTypeEnum... types)
  76. {
  77. return contentType(nullSafeCollection(types));
  78. }
  79. @SuppressWarnings("unchecked")
  80. public SearchQuery build()
  81. {
  82. BooleanQueryBuilder finalQuery = new BooleanQueryBuilder();
  83. filter(createdByUsers, NotNullPredicate.INSTANCE);
  84. filter(lastModifiedByUsers, NotNullPredicate.INSTANCE);
  85. if (isNotEmpty(createdByUsers) || isNotEmpty(lastModifiedByUsers))
  86. {
  87. BooleanQueryBuilder usersQuery = new BooleanQueryBuilder();
  88. if (isNotEmpty(createdByUsers))
  89. {
  90. usersQuery.or(collect(createdByUsers, UserNameToCreatorQueryTransformer.INSTANCE,
  91. new HashSet<SearchQuery>(createdByUsers.size())));
  92. }
  93. if (isNotEmpty(lastModifiedByUsers))
  94. {
  95. usersQuery.or(collect(lastModifiedByUsers, UserNameToLastModifierQueryTransformer.INSTANCE,
  96. new HashSet<SearchQuery>(lastModifiedByUsers.size())));
  97. }
  98. finalQuery.and(usersQuery);
  99. }
  100. filter(spaceKeys, NotNullPredicate.INSTANCE);
  101. if (isNotEmpty(spaceKeys))
  102. {
  103. finalQuery.and(new InSpaceQuery(new HashSet<String>(spaceKeys)));
  104. }
  105. filter(searchTerms, NotNullPredicate.INSTANCE);
  106. if (isNotEmpty(searchTerms))
  107. {
  108. finalQuery.and(buildMultiTextFieldQuery(searchTerms));
  109. }
  110. filter(contentTypes, NotNullPredicate.INSTANCE);
  111. if (isNotEmpty(contentTypes))
  112. {
  113. finalQuery.and(new ContentTypeQuery(contentTypes));
  114. }
  115. return finalQuery.build();
  116. }
  117. private static SearchQuery buildMultiTextFieldQuery(Set<String> keywords)
  118. {
  119. StringBuilder sb = new StringBuilder();
  120. for (String keyword : keywords)
  121. {
  122. if (sb.length() > 0)
  123. sb.append(' ');
  124. sb.append(keyword);
  125. }
  126. return new MultiTextFieldQuery(sb.toString(), TEXT_FIELDS);
  127. }
  128. private static <T> Collection<T> nullSafeCollection(T[] source)
  129. {
  130. if (source == null)
  131. {
  132. return Collections.emptyList();
  133. }
  134. return Arrays.asList(source);
  135. }
  136. private static <T> Collection<T> nullSafeCollection(Collection<T> source)
  137. {
  138. if (source == null)
  139. {
  140. return Collections.emptyList();
  141. }
  142. return source;
  143. }
  144. static class StringTrimmer implements Transformer
  145. {
  146. public static StringTrimmer INSTANCE = new StringTrimmer();
  147. private StringTrimmer()
  148. {
  149. super();
  150. }
  151. public Object transform(Object input)
  152. {
  153. return trimToNull((String)input);
  154. }
  155. }
  156. static class UserNameToCreatorQueryTransformer implements Transformer
  157. {
  158. public static UserNameToCreatorQueryTransformer INSTANCE =
  159. new UserNameToCreatorQueryTransformer();
  160. private UserNameToCreatorQueryTransformer()
  161. {
  162. super();
  163. }
  164. public Object transform(Object input)
  165. {
  166. String userName = (String) input;
  167. return isBlank(userName) ? null : new CreatorQuery(userName);
  168. }
  169. }
  170. static class UserNameToLastModifierQueryTransformer implements Transformer
  171. {
  172. public static UserNameToLastModifierQueryTransformer INSTANCE =
  173. new UserNameToLastModifierQueryTransformer();
  174. private UserNameToLastModifierQueryTransformer()
  175. {
  176. super();
  177. }
  178. public Object transform(Object input)
  179. {
  180. String userName = (String) input;
  181. return isBlank(userName) ? null : new LastModifierQuery(userName);
  182. }
  183. }
  184. static class BooleanQueryBuilder
  185. {
  186. private Boolean isAndQuery;
  187. private final Set<SearchQuery> queries;
  188. private BooleanQueryBuilder()
  189. {
  190. queries = new HashSet<SearchQuery>();
  191. }
  192. BooleanQueryBuilder and(Collection<SearchQuery> queries)
  193. {
  194. if (isAndQuery != null && !isAndQuery)
  195. {
  196. throw new IllegalStateException(
  197. "AND operation not permitted as a previous OR operation has been called.");
  198. }
  199. isAndQuery = true;
  200. this.queries.addAll(checkNotNull(queries, "Sub queries"));
  201. return this;
  202. }
  203. BooleanQueryBuilder and(SearchQuery... queries)
  204. {
  205. return and(Arrays.asList(checkNotNull(queries, "Sub queries")));
  206. }
  207. BooleanQueryBuilder and(BooleanQueryBuilder queryBuilder)
  208. {
  209. return and(queryBuilder.build());
  210. }
  211. BooleanQueryBuilder or(Collection<SearchQuery> queries)
  212. {
  213. if (isAndQuery != null && isAndQuery)
  214. {
  215. throw new IllegalStateException(
  216. "OR operation not permitted as a previous AND operation has been called.");
  217. }
  218. isAndQuery = false;
  219. this.queries.addAll(checkNotNull(queries, "Sub queries"));
  220. return this;
  221. }
  222. BooleanQueryBuilder or(SearchQuery... queries)
  223. {
  224. return or(Arrays.asList(checkNotNull(queries, "Sub queries")));
  225. }
  226. BooleanQueryBuilder or(BooleanQueryBuilder queryBuilder)
  227. {
  228. return or(queryBuilder.build());
  229. }
  230. SearchQuery build()
  231. {
  232. if (queries.isEmpty())
  233. {
  234. throw new IllegalStateException("New subqueries added.");
  235. }
  236. SearchQuery result =
  237. isAndQuery ? BooleanQuery.composeAndQuery(queries) : BooleanQuery.composeOrQuery(queries);
  238. isAndQuery = null;
  239. queries.clear();
  240. return result;
  241. }
  242. }
  243. }