View Javadoc

1   package org.apache.maven.plugin.jira;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.UnsupportedEncodingException;
23  import java.net.URLEncoder;
24  import java.util.Locale;
25  
26  import org.apache.maven.plugin.logging.Log;
27  
28  /**
29   * Builder for a JIRA query using the JIRA query language.
30   * Only a limited set of JQL is supported.
31   *
32   * @author ton.swieb@finalist.com
33   * @version $Id: JqlQueryBuilder.java 1380001 2012-09-02 16:00:59Z dennisl $
34   * @since 2.8
35   */
36  public class JqlQueryBuilder
37      implements JiraQueryBuilder
38  {
39      private String filter = "";
40  
41      /**
42       * Log for debug output.
43       */
44      private Log log;
45  
46      private StringBuilder orderBy = new StringBuilder();
47  
48      private StringBuilder query = new StringBuilder();
49  
50      public JqlQueryBuilder( Log log )
51      {
52          this.log = log;
53      }
54  
55      public String build()
56      {
57          try
58          {
59              String jqlQuery;
60              // If the user has defined a filter - use that
61              if ( ( this.filter != null ) && ( this.filter.length() > 0 ) )
62              {
63                  jqlQuery = filter;
64              }
65              else
66              {
67                  jqlQuery = query.toString() + orderBy.toString();
68              }
69              getLog().debug( "Encoding JQL query " + jqlQuery );
70              String encodedQuery = URLEncoder.encode( jqlQuery, "UTF-8" );
71              getLog().debug( "Encoded JQL query " + encodedQuery );
72              return encodedQuery;
73          }
74          catch ( UnsupportedEncodingException e )
75          {
76              getLog().error( "Unable to encode JQL query with UTF-8", e );
77              throw new RuntimeException( e );
78          }
79      }
80  
81      public JiraQueryBuilder components( String components )
82      {
83          addCommaSeparatedValues( "component", components );
84          return this;
85      }
86  
87      public JiraQueryBuilder filter( String filter )
88      {
89          this.filter = filter;
90          return this;
91      }
92  
93      /**
94       * When both {@link #fixVersion(String)} and {@link #fixVersionIds(String)} are used then you will probably
95       * end up with a JQL query that is valid, but returns nothing. Unless they both only reference the same fixVersion
96       *
97       * @param fixVersion
98       * @return
99       */
100     public JiraQueryBuilder fixVersion( String fixVersion )
101     {
102         addSingleValue( "fixVersion", fixVersion );
103         return this;
104     }
105 
106     /**
107      * When both {@link #fixVersion(String)} and {@link #fixVersionIds(String)} are used then you will probably
108      * end up with a JQL query that is valid, but returns nothing. Unless they both only reference the same fixVersion
109      *
110      * @param fixVersionIds
111      * @return
112      */
113     public JiraQueryBuilder fixVersionIds( String fixVersionIds )
114     {
115         addCommaSeparatedValues( "fixVersion", fixVersionIds );
116         return this;
117     }
118 
119     public Log getLog()
120     {
121         return log;
122     }
123 
124     public JiraQueryBuilder priorityIds( String priorityIds )
125     {
126         addCommaSeparatedValues( "priority", priorityIds );
127         return this;
128     }
129 
130     public JiraQueryBuilder project( String project )
131     {
132         addSingleValue( "project", project );
133         return this;
134     }
135 
136     public JiraQueryBuilder resolutionIds( String resolutionIds )
137     {
138         addCommaSeparatedValues( "resolution", resolutionIds );
139         return this;
140     }
141 
142     public JiraQueryBuilder sortColumnNames( String sortColumnNames )
143     {
144         if ( sortColumnNames != null )
145         {
146             orderBy.append( " ORDER BY " );
147 
148             String[] sortColumnNamesArray = sortColumnNames.split( "," );
149 
150             for ( int i = 0; i < sortColumnNamesArray.length - 1; i++ )
151             {
152                 addSingleSortColumn( sortColumnNamesArray[i] );
153                 orderBy.append( ", " );
154             }
155             addSingleSortColumn( sortColumnNamesArray[sortColumnNamesArray.length - 1] );
156         }
157         return this;
158     }
159 
160     public JiraQueryBuilder statusIds( String statusIds )
161     {
162         addCommaSeparatedValues( "status", statusIds );
163         return this;
164     }
165 
166 
167     public JiraQueryBuilder typeIds( String typeIds )
168     {
169         addCommaSeparatedValues( "type", typeIds );
170         return this;
171     }
172 
173     /* --------------------------------------------------------------------- */
174     /* Private methods                                                       */
175     /* --------------------------------------------------------------------- */
176 
177     private void addCommaSeparatedValues( String key, String values )
178     {
179         if ( values != null )
180         {
181             if ( query.length() > 0 )
182             {
183                 query.append( " AND " );
184             }
185 
186             query.append( key + " in (" );
187 
188             String[] valuesArr = values.split( "," );
189 
190             for ( int i = 0; i < ( valuesArr.length - 1 ); i++ )
191             {
192                 trimAndQuoteValue( valuesArr[i] );
193                 query.append( ", " );
194             }
195             trimAndQuoteValue( valuesArr[valuesArr.length - 1] );
196             query.append( ")" );
197         }
198     }
199 
200     private void addSingleSortColumn( String name )
201     {
202         boolean descending = false;
203         name = name.trim().toLowerCase( Locale.ENGLISH );
204         if ( name.endsWith( "desc" ) )
205         {
206             descending = true;
207             name = name.substring( 0, name.length() - 4 ).trim();
208         }
209         else if ( name.endsWith( "asc" ) )
210         {
211             descending = false;
212             name = name.substring( 0, name.length() - 3 ).trim();
213         }
214         // Strip any spaces from the column name, or it will trip up JIRA's JQL parser
215         name = name.replaceAll( " ", "" );
216         orderBy.append( name );
217         orderBy.append( descending ? " DESC" : " ASC" );
218     }
219 
220     private void addSingleValue( String key, String value )
221     {
222         if ( value != null )
223         {
224             if ( query.length() > 0 )
225             {
226                 query.append( " AND " );
227             }
228             query.append( key ).append( " = " );
229             trimAndQuoteValue( value );
230         }
231     }
232 
233     private void trimAndQuoteValue( String value )
234     {
235         String trimmedValue = value.trim();
236         if ( trimmedValue.contains( " " ) || trimmedValue.contains( "." ) )
237         {
238             query.append( "\"" ).append( trimmedValue ).append( "\"" );
239         }
240         else
241         {
242             query.append( trimmedValue );
243         }
244     }
245 }