001/* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2013 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * SonarQube is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * SonarQube is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020package org.sonar.api.issue; 021 022import com.google.common.base.Preconditions; 023import com.google.common.collect.ImmutableSet; 024import org.apache.commons.lang.builder.ReflectionToStringBuilder; 025import org.sonar.api.rule.RuleKey; 026import org.sonar.api.web.UserRole; 027 028import javax.annotation.CheckForNull; 029import javax.annotation.Nullable; 030 031import java.util.Collection; 032import java.util.Date; 033import java.util.Set; 034 035/** 036 * @since 3.6 037 */ 038public class IssueQuery { 039 040 public static final int DEFAULT_PAGE_INDEX = 1; 041 public static final int DEFAULT_PAGE_SIZE = 100; 042 public static final int MAX_RESULTS = 10000; 043 public static final int MAX_PAGE_SIZE = 500; 044 public static final int MAX_ISSUE_KEYS = 500; 045 046 public static final String SORT_BY_CREATION_DATE = "CREATION_DATE"; 047 public static final String SORT_BY_UPDATE_DATE = "UPDATE_DATE"; 048 public static final String SORT_BY_CLOSE_DATE = "CLOSE_DATE"; 049 public static final String SORT_BY_ASSIGNEE = "ASSIGNEE"; 050 public static final String SORT_BY_SEVERITY = "SEVERITY"; 051 public static final String SORT_BY_STATUS = "STATUS"; 052 public static final Set<String> SORTS = ImmutableSet.of(SORT_BY_CREATION_DATE, SORT_BY_UPDATE_DATE, SORT_BY_CLOSE_DATE, SORT_BY_ASSIGNEE, SORT_BY_SEVERITY, SORT_BY_STATUS); 053 054 private final Collection<String> issueKeys; 055 private final Collection<String> severities; 056 private final Collection<String> statuses; 057 private final Collection<String> resolutions; 058 private final Collection<String> components; 059 private final Collection<String> componentRoots; 060 private final Collection<RuleKey> rules; 061 private final Collection<String> actionPlans; 062 private final Collection<String> reporters; 063 private final Collection<String> assignees; 064 private final Boolean assigned; 065 private final Boolean planned; 066 private final Boolean resolved; 067 private final Date createdAfter; 068 private final Date createdBefore; 069 private final String sort; 070 private final Boolean asc; 071 private final String requiredRole; 072 073 // max results per page 074 private final int pageSize; 075 076 // index of selected page. Start with 1. 077 private final int pageIndex; 078 079 private IssueQuery(Builder builder) { 080 this.issueKeys = builder.issueKeys; 081 this.severities = builder.severities; 082 this.statuses = builder.statuses; 083 this.resolutions = builder.resolutions; 084 this.components = builder.components; 085 this.componentRoots = builder.componentRoots; 086 this.rules = builder.rules; 087 this.actionPlans = builder.actionPlans; 088 this.reporters = builder.reporters; 089 this.assignees = builder.assignees; 090 this.assigned = builder.assigned; 091 this.planned = builder.planned; 092 this.resolved = builder.resolved; 093 this.createdAfter = builder.createdAfter; 094 this.createdBefore = builder.createdBefore; 095 this.sort = builder.sort; 096 this.asc = builder.asc; 097 this.pageSize = builder.pageSize; 098 this.pageIndex = builder.pageIndex; 099 this.requiredRole = builder.requiredRole; 100 } 101 102 public Collection<String> issueKeys() { 103 return issueKeys; 104 } 105 106 public Collection<String> severities() { 107 return severities; 108 } 109 110 public Collection<String> statuses() { 111 return statuses; 112 } 113 114 public Collection<String> resolutions() { 115 return resolutions; 116 } 117 118 public Collection<String> components() { 119 return components; 120 } 121 122 public Collection<String> componentRoots() { 123 return componentRoots; 124 } 125 126 public Collection<RuleKey> rules() { 127 return rules; 128 } 129 130 public Collection<String> actionPlans() { 131 return actionPlans; 132 } 133 134 public Collection<String> reporters() { 135 return reporters; 136 } 137 138 public Collection<String> assignees() { 139 return assignees; 140 } 141 142 @CheckForNull 143 public Boolean assigned() { 144 return assigned; 145 } 146 147 @CheckForNull 148 public Boolean planned() { 149 return planned; 150 } 151 152 @CheckForNull 153 public Boolean resolved() { 154 return resolved; 155 } 156 157 @CheckForNull 158 public Date createdAfter() { 159 return createdAfter; 160 } 161 162 @CheckForNull 163 public Date createdBefore() { 164 return createdBefore; 165 } 166 167 @CheckForNull 168 public String sort() { 169 return sort; 170 } 171 172 @CheckForNull 173 public Boolean asc() { 174 return asc; 175 } 176 177 public int pageSize() { 178 return pageSize; 179 } 180 181 public int pageIndex() { 182 return pageIndex; 183 } 184 185 public int maxResults() { 186 return MAX_RESULTS; 187 } 188 189 public String requiredRole() { 190 return requiredRole; 191 } 192 193 @Override 194 public String toString() { 195 return ReflectionToStringBuilder.toString(this); 196 } 197 198 public static Builder builder() { 199 return new Builder(); 200 } 201 202 public static class Builder { 203 private Collection<String> issueKeys; 204 private Collection<String> severities; 205 private Collection<String> statuses; 206 private Collection<String> resolutions; 207 private Collection<String> components; 208 private Collection<String> componentRoots; 209 private Collection<RuleKey> rules; 210 private Collection<String> actionPlans; 211 private Collection<String> reporters; 212 private Collection<String> assignees; 213 private Boolean assigned = null; 214 private Boolean planned = null; 215 private Boolean resolved = null; 216 private Date createdAfter; 217 private Date createdBefore; 218 private String sort; 219 private Boolean asc = false; 220 private Integer pageSize; 221 private Integer pageIndex; 222 private String requiredRole = UserRole.USER; 223 224 private Builder() { 225 } 226 227 public Builder issueKeys(Collection<String> l) { 228 this.issueKeys = l; 229 return this; 230 } 231 232 public Builder severities(Collection<String> l) { 233 this.severities = l; 234 return this; 235 } 236 237 public Builder statuses(Collection<String> l) { 238 this.statuses = l; 239 return this; 240 } 241 242 public Builder resolutions(Collection<String> l) { 243 this.resolutions = l; 244 return this; 245 } 246 247 public Builder components(Collection<String> l) { 248 this.components = l; 249 return this; 250 } 251 252 public Builder componentRoots(Collection<String> l) { 253 this.componentRoots = l; 254 return this; 255 } 256 257 public Builder rules(Collection<RuleKey> rules) { 258 this.rules = rules; 259 return this; 260 } 261 262 public Builder actionPlans(Collection<String> l) { 263 this.actionPlans = l; 264 return this; 265 } 266 267 public Builder reporters(Collection<String> l) { 268 this.reporters = l; 269 return this; 270 } 271 272 public Builder assignees(Collection<String> l) { 273 this.assignees = l; 274 return this; 275 } 276 277 /** 278 * If true, it will return all issues assigned to someone 279 * If false, it will return all issues not assigned to someone 280 */ 281 public Builder assigned(@Nullable Boolean b) { 282 this.assigned = b; 283 return this; 284 } 285 286 /** 287 * If true, it will return all issues linked to an action plan 288 * If false, it will return all issues not linked to an action plan 289 */ 290 public Builder planned(@Nullable Boolean planned) { 291 this.planned = planned; 292 return this; 293 } 294 295 /** 296 * If true, it will return all resolved issues 297 * If false, it will return all none resolved issues 298 */ 299 public Builder resolved(@Nullable Boolean resolved) { 300 this.resolved = resolved; 301 return this; 302 } 303 304 public Builder createdAfter(@Nullable Date d) { 305 this.createdAfter = d; 306 return this; 307 } 308 309 public Builder createdBefore(@Nullable Date d) { 310 this.createdBefore = d; 311 return this; 312 } 313 314 public Builder sort(@Nullable String s) { 315 if (s != null && !SORTS.contains(s)) { 316 throw new IllegalArgumentException("Bad sort field: " + s); 317 } 318 this.sort = s; 319 return this; 320 } 321 322 public Builder asc(@Nullable Boolean asc) { 323 this.asc = asc; 324 return this; 325 } 326 327 public Builder pageSize(@Nullable Integer i) { 328 this.pageSize = i; 329 return this; 330 } 331 332 public Builder pageIndex(@Nullable Integer i) { 333 this.pageIndex = i; 334 return this; 335 } 336 337 public Builder requiredRole(@Nullable String s) { 338 this.requiredRole = s; 339 return this; 340 } 341 342 public IssueQuery build() { 343 initPageIndex(); 344 initPageSize(); 345 if (issueKeys != null) { 346 Preconditions.checkArgument(issueKeys.size() < MAX_ISSUE_KEYS, "Number of issue keys must be less than " + MAX_ISSUE_KEYS + " (got " + issueKeys.size() + ")"); 347 } 348 return new IssueQuery(this); 349 } 350 351 private void initPageSize() { 352 if (components != null && components.size() == 1 && pageSize == null) { 353 pageSize = 999999; 354 } else { 355 if (pageSize == null) { 356 pageSize = DEFAULT_PAGE_SIZE; 357 } else if (pageSize <= 0 || pageSize > MAX_PAGE_SIZE) { 358 pageSize = MAX_PAGE_SIZE; 359 } 360 } 361 } 362 363 private void initPageIndex() { 364 if (pageIndex == null) { 365 pageIndex = DEFAULT_PAGE_INDEX; 366 } 367 Preconditions.checkArgument(pageIndex > 0, "Page index must be greater than 0 (got " + pageIndex + ")"); 368 } 369 } 370}