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 }