1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.changes.jira;
20
21 import java.io.UnsupportedEncodingException;
22 import java.net.URLEncoder;
23 import java.util.Arrays;
24 import java.util.List;
25 import java.util.Locale;
26
27 import org.apache.commons.lang3.ArraySorter;
28 import org.apache.maven.plugin.logging.Log;
29
30
31
32
33
34
35
36
37 public class JqlQueryBuilder {
38
39
40
41
42 private static final String[] RESERVED_JQL_WORDS = ArraySorter.sort(new String[] {
43 "abort",
44 "access",
45 "add",
46 "after",
47 "alias",
48 "all",
49 "alter",
50 "and",
51 "any",
52 "as",
53 "asc",
54 "audit",
55 "avg",
56 "before",
57 "begin",
58 "between",
59 "boolean",
60 "break",
61 "by",
62 "byte",
63 "catch",
64 "cf",
65 "char",
66 "character",
67 "check",
68 "checkpoint",
69 "collate",
70 "collation",
71 "column",
72 "commit",
73 "connect",
74 "continue",
75 "count",
76 "create",
77 "current",
78 "date",
79 "decimal",
80 "declare",
81 "decrement",
82 "default",
83 "defaults",
84 "define",
85 "delete",
86 "delimiter",
87 "desc",
88 "difference",
89 "distinct",
90 "divide",
91 "do",
92 "double",
93 "drop",
94 "else",
95 "empty",
96 "encoding",
97 "end",
98 "equals",
99 "escape",
100 "exclusive",
101 "exec",
102 "execute",
103 "exists",
104 "explain",
105 "false",
106 "fetch",
107 "file",
108 "field",
109 "first",
110 "float",
111 "for",
112 "from",
113 "function",
114 "go",
115 "goto",
116 "grant",
117 "greater",
118 "group",
119 "having",
120 "identified",
121 "if",
122 "immediate",
123 "in",
124 "increment",
125 "index",
126 "initial",
127 "inner",
128 "inout",
129 "input",
130 "insert",
131 "int",
132 "integer",
133 "intersect",
134 "intersection",
135 "into",
136 "is",
137 "isempty",
138 "isnull",
139 "join",
140 "last",
141 "left",
142 "less",
143 "like",
144 "limit",
145 "lock",
146 "long",
147 "max",
148 "min",
149 "minus",
150 "mode",
151 "modify",
152 "modulo",
153 "more",
154 "multiply",
155 "next",
156 "noaudit",
157 "not",
158 "notin",
159 "nowait",
160 "null",
161 "number",
162 "object",
163 "of",
164 "on",
165 "option",
166 "or",
167 "order",
168 "outer",
169 "output",
170 "power",
171 "previous",
172 "prior",
173 "privileges",
174 "public",
175 "raise",
176 "raw",
177 "remainder",
178 "rename",
179 "resource",
180 "return",
181 "returns",
182 "revoke",
183 "right",
184 "row",
185 "rowid",
186 "rownum",
187 "rows",
188 "select",
189 "session",
190 "set",
191 "share",
192 "size",
193 "sqrt",
194 "start",
195 "strict",
196 "string",
197 "subtract",
198 "sum",
199 "synonym",
200 "table",
201 "then",
202 "to",
203 "trans",
204 "transaction",
205 "trigger",
206 "true",
207 "uid",
208 "union",
209 "unique",
210 "update",
211 "user",
212 "validate",
213 "values",
214 "view",
215 "when",
216 "whenever",
217 "where",
218 "while",
219 "with"
220 });
221
222 private String filter = "";
223
224 private boolean urlEncode = true;
225
226
227
228
229 private Log log;
230
231 private StringBuilder orderBy = new StringBuilder();
232
233 private StringBuilder query = new StringBuilder();
234
235 public JqlQueryBuilder(Log log) {
236 this.log = log;
237 }
238
239 public String build() {
240 try {
241 String jqlQuery;
242
243 if (filter != null && !filter.isEmpty()) {
244 jqlQuery = filter;
245 } else {
246 jqlQuery = query.toString() + orderBy.toString();
247 }
248
249 if (urlEncode) {
250 getLog().debug("Encoding JQL query " + jqlQuery);
251 String encodedQuery = URLEncoder.encode(jqlQuery, "UTF-8");
252 getLog().debug("Encoded JQL query " + encodedQuery);
253 return encodedQuery;
254 } else {
255 return jqlQuery;
256 }
257 } catch (UnsupportedEncodingException e) {
258 getLog().error("Unable to encode JQL query with UTF-8", e);
259 throw new RuntimeException(e);
260 }
261 }
262
263 public JqlQueryBuilder components(String components) {
264 addCommaSeparatedValues("component", components);
265 return this;
266 }
267
268 public JqlQueryBuilder components(List<String> components) {
269 addValues("component", components);
270 return this;
271 }
272
273 public JqlQueryBuilder filter(String filter) {
274 this.filter = filter;
275 return this;
276 }
277
278
279
280
281
282
283
284
285 public JqlQueryBuilder fixVersion(String fixVersion) {
286 addSingleValue("fixVersion", fixVersion);
287 return this;
288 }
289
290
291
292
293
294
295
296
297 public JqlQueryBuilder fixVersionIds(String fixVersionIds) {
298 addCommaSeparatedValues("fixVersion", fixVersionIds);
299 return this;
300 }
301
302
303
304
305
306
307
308 public JqlQueryBuilder fixVersionIds(List<String> fixVersionIds) {
309 addValues("fixVersion", fixVersionIds);
310 return this;
311 }
312
313 public Log getLog() {
314 return log;
315 }
316
317 public JqlQueryBuilder priorityIds(String priorityIds) {
318 addCommaSeparatedValues("priority", priorityIds);
319 return this;
320 }
321
322 public JqlQueryBuilder priorityIds(List<String> priorityIds) {
323 addValues("priority", priorityIds);
324 return this;
325 }
326
327 public JqlQueryBuilder project(String project) {
328 addSingleValue("project", project);
329 return this;
330 }
331
332 public JqlQueryBuilder resolutionIds(String resolutionIds) {
333 addCommaSeparatedValues("resolution", resolutionIds);
334 return this;
335 }
336
337 public JqlQueryBuilder resolutionIds(List<String> resolutionIds) {
338 addValues("resolution", resolutionIds);
339 return this;
340 }
341
342 public JqlQueryBuilder sortColumnNames(String sortColumnNames) {
343 if (sortColumnNames != null) {
344 orderBy.append(" ORDER BY ");
345
346 String[] sortColumnNamesArray = sortColumnNames.split(",");
347
348 for (int i = 0; i < sortColumnNamesArray.length - 1; i++) {
349 addSingleSortColumn(sortColumnNamesArray[i]);
350 orderBy.append(", ");
351 }
352 addSingleSortColumn(sortColumnNamesArray[sortColumnNamesArray.length - 1]);
353 }
354 return this;
355 }
356
357 public JqlQueryBuilder statusIds(String statusIds) {
358 addCommaSeparatedValues("status", statusIds);
359 return this;
360 }
361
362 public JqlQueryBuilder statusIds(List<String> statusIds) {
363 addValues("status", statusIds);
364 return this;
365 }
366
367 public JqlQueryBuilder typeIds(String typeIds) {
368 addCommaSeparatedValues("type", typeIds);
369 return this;
370 }
371
372 public JqlQueryBuilder typeIds(List<String> typeIds) {
373 addValues("type", typeIds);
374 return this;
375 }
376
377 public JqlQueryBuilder urlEncode(boolean doEncoding) {
378 urlEncode = doEncoding;
379 return this;
380 }
381
382 public boolean urlEncode() {
383 return urlEncode;
384 }
385
386
387
388
389
390 private void addCommaSeparatedValues(String key, String values) {
391 if (values != null) {
392 if (query.length() > 0) {
393 query.append(" AND ");
394 }
395
396 query.append(key).append(" in (");
397
398 String[] valuesArr = values.split(",");
399
400 for (int i = 0; i < (valuesArr.length - 1); i++) {
401 trimAndQuoteValue(valuesArr[i]);
402 query.append(", ");
403 }
404 trimAndQuoteValue(valuesArr[valuesArr.length - 1]);
405 query.append(")");
406 }
407 }
408
409 private void addValues(String key, List<String> values) {
410 if (values != null && !values.isEmpty()) {
411 if (query.length() > 0) {
412 query.append(" AND ");
413 }
414
415 query.append(key).append(" in (");
416
417 for (int i = 0; i < (values.size() - 1); i++) {
418 trimAndQuoteValue(values.get(i));
419 query.append(", ");
420 }
421 trimAndQuoteValue(values.get(values.size() - 1));
422 query.append(")");
423 }
424 }
425
426 private void addSingleSortColumn(String name) {
427 boolean descending = false;
428 name = name.trim().toLowerCase(Locale.ENGLISH);
429 if (name.endsWith("desc")) {
430 descending = true;
431 name = name.substring(0, name.length() - 4).trim();
432 } else if (name.endsWith("asc")) {
433 descending = false;
434 name = name.substring(0, name.length() - 3).trim();
435 }
436
437 name = name.replaceAll(" ", "");
438 orderBy.append(name);
439 orderBy.append(descending ? " DESC" : " ASC");
440 }
441
442 private void addSingleValue(String key, String value) {
443 if (value != null) {
444 if (query.length() > 0) {
445 query.append(" AND ");
446 }
447 query.append(key).append(" = ");
448 trimAndQuoteValue(value);
449 }
450 }
451
452 private void trimAndQuoteValue(String value) {
453 String trimmedValue = value.trim();
454 if (trimmedValue.contains(" ") || trimmedValue.contains(".") || isReservedJqlWord(trimmedValue)) {
455 query.append("\"").append(trimmedValue).append("\"");
456 } else {
457 query.append(trimmedValue);
458 }
459 }
460
461
462
463
464
465
466
467 private boolean isReservedJqlWord(String value) {
468 return Arrays.binarySearch(RESERVED_JQL_WORDS, value.toLowerCase(Locale.ROOT)) > 0;
469 }
470 }