001 /* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2014 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 */ 020 package org.sonar.api.issue; 021 022 import com.google.common.base.Preconditions; 023 import com.google.common.collect.ImmutableSet; 024 import org.apache.commons.lang.builder.ReflectionToStringBuilder; 025 import org.sonar.api.rule.RuleKey; 026 import org.sonar.api.web.UserRole; 027 028 import javax.annotation.CheckForNull; 029 import javax.annotation.Nullable; 030 031 import java.util.Collection; 032 import java.util.Collections; 033 import java.util.Date; 034 import java.util.Set; 035 036 /** 037 * @since 3.6 038 */ 039 public class IssueQuery { 040 041 public static final int DEFAULT_PAGE_INDEX = 1; 042 public static final int DEFAULT_PAGE_SIZE = 100; 043 public static final int MAX_RESULTS = 10000; 044 public static final int MAX_PAGE_SIZE = 500; 045 046 /** 047 * @deprecated since 3.7. It's replaced by IssueQuery#MAX_PAGE_SIZE. 048 */ 049 @Deprecated 050 public static final int MAX_ISSUE_KEYS = MAX_PAGE_SIZE; 051 052 public static final String SORT_BY_CREATION_DATE = "CREATION_DATE"; 053 public static final String SORT_BY_UPDATE_DATE = "UPDATE_DATE"; 054 public static final String SORT_BY_CLOSE_DATE = "CLOSE_DATE"; 055 public static final String SORT_BY_ASSIGNEE = "ASSIGNEE"; 056 public static final String SORT_BY_SEVERITY = "SEVERITY"; 057 public static final String SORT_BY_STATUS = "STATUS"; 058 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); 059 060 private final Collection<String> issueKeys; 061 private final Collection<String> severities; 062 private final Collection<String> statuses; 063 private final Collection<String> resolutions; 064 private final Collection<String> components; 065 private final Collection<String> componentRoots; 066 private final Collection<RuleKey> rules; 067 private final Collection<String> actionPlans; 068 private final Collection<String> reporters; 069 private final Collection<String> assignees; 070 private final Collection<String> languages; 071 private final Boolean assigned; 072 private final Boolean planned; 073 private final Boolean resolved; 074 private final Boolean hideRules; 075 private final Date createdAt; 076 private final Date createdAfter; 077 private final Date createdBefore; 078 private final String sort; 079 private final Boolean asc; 080 private final String requiredRole; 081 082 // max results per page 083 private final int pageSize; 084 085 // index of selected page. Start with 1. 086 private final int pageIndex; 087 088 private IssueQuery(Builder builder) { 089 this.issueKeys = defaultCollection(builder.issueKeys); 090 this.severities = defaultCollection(builder.severities); 091 this.statuses = defaultCollection(builder.statuses); 092 this.resolutions = defaultCollection(builder.resolutions); 093 this.components = defaultCollection(builder.components); 094 this.componentRoots = defaultCollection(builder.componentRoots); 095 this.rules = defaultCollection(builder.rules); 096 this.actionPlans = defaultCollection(builder.actionPlans); 097 this.reporters = defaultCollection(builder.reporters); 098 this.assignees = defaultCollection(builder.assignees); 099 this.languages = defaultCollection(builder.languages); 100 this.assigned = builder.assigned; 101 this.planned = builder.planned; 102 this.resolved = builder.resolved; 103 this.hideRules = builder.hideRules; 104 this.createdAt = builder.createdAt; 105 this.createdAfter = builder.createdAfter; 106 this.createdBefore = builder.createdBefore; 107 this.sort = builder.sort; 108 this.asc = builder.asc; 109 this.pageSize = builder.pageSize; 110 this.pageIndex = builder.pageIndex; 111 this.requiredRole = builder.requiredRole; 112 } 113 114 public Collection<String> issueKeys() { 115 return issueKeys; 116 } 117 118 public Collection<String> severities() { 119 return severities; 120 } 121 122 public Collection<String> statuses() { 123 return statuses; 124 } 125 126 public Collection<String> resolutions() { 127 return resolutions; 128 } 129 130 public Collection<String> components() { 131 return components; 132 } 133 134 public Collection<String> componentRoots() { 135 return componentRoots; 136 } 137 138 public Collection<RuleKey> rules() { 139 return rules; 140 } 141 142 public Collection<String> actionPlans() { 143 return actionPlans; 144 } 145 146 public Collection<String> reporters() { 147 return reporters; 148 } 149 150 public Collection<String> assignees() { 151 return assignees; 152 } 153 public Collection<String> languages() { 154 return languages; 155 } 156 157 @CheckForNull 158 public Boolean assigned() { 159 return assigned; 160 } 161 162 @CheckForNull 163 public Boolean planned() { 164 return planned; 165 } 166 167 @CheckForNull 168 public Boolean resolved() { 169 return resolved; 170 } 171 172 /** 173 * @since 4.2 174 */ 175 @CheckForNull 176 public Boolean hideRules() { 177 return hideRules; 178 } 179 180 @CheckForNull 181 public Date createdAfter() { 182 return createdAfter == null ? null : new Date(createdAfter.getTime()); 183 } 184 185 @CheckForNull 186 public Date createdAt() { 187 return createdAt == null ? null : new Date(createdAt.getTime()); 188 } 189 190 @CheckForNull 191 public Date createdBefore() { 192 return createdBefore == null ? null : new Date(createdBefore.getTime()); 193 } 194 195 @CheckForNull 196 public String sort() { 197 return sort; 198 } 199 200 @CheckForNull 201 public Boolean asc() { 202 return asc; 203 } 204 205 public int pageSize() { 206 return pageSize; 207 } 208 209 public int pageIndex() { 210 return pageIndex; 211 } 212 213 public int maxResults() { 214 return MAX_RESULTS; 215 } 216 217 public String requiredRole() { 218 return requiredRole; 219 } 220 221 @Override 222 public String toString() { 223 return ReflectionToStringBuilder.toString(this); 224 } 225 226 public static Builder builder() { 227 return new Builder(); 228 } 229 230 public static class Builder { 231 private Collection<String> issueKeys; 232 private Collection<String> severities; 233 private Collection<String> statuses; 234 private Collection<String> resolutions; 235 private Collection<String> components; 236 private Collection<String> componentRoots; 237 private Collection<RuleKey> rules; 238 private Collection<String> actionPlans; 239 private Collection<String> reporters; 240 private Collection<String> assignees; 241 private Collection<String> languages; 242 private Boolean assigned = null; 243 private Boolean planned = null; 244 private Boolean resolved = null; 245 private Boolean hideRules = false; 246 private Date createdAt; 247 private Date createdAfter; 248 private Date createdBefore; 249 private String sort; 250 private Boolean asc = false; 251 private Integer pageSize; 252 private Integer pageIndex; 253 private String requiredRole = UserRole.USER; 254 255 private Builder() { 256 } 257 258 public Builder issueKeys(@Nullable Collection<String> l) { 259 this.issueKeys = l; 260 return this; 261 } 262 263 public Builder severities(@Nullable Collection<String> l) { 264 this.severities = l; 265 return this; 266 } 267 268 public Builder statuses(@Nullable Collection<String> l) { 269 this.statuses = l; 270 return this; 271 } 272 273 public Builder resolutions(@Nullable Collection<String> l) { 274 this.resolutions = l; 275 return this; 276 } 277 278 public Builder components(@Nullable Collection<String> l) { 279 this.components = l; 280 return this; 281 } 282 283 public Builder componentRoots(@Nullable Collection<String> l) { 284 this.componentRoots = l; 285 return this; 286 } 287 288 public Builder rules(@Nullable Collection<RuleKey> rules) { 289 this.rules = rules; 290 return this; 291 } 292 293 public Builder actionPlans(@Nullable Collection<String> l) { 294 this.actionPlans = l; 295 return this; 296 } 297 298 public Builder reporters(@Nullable Collection<String> l) { 299 this.reporters = l; 300 return this; 301 } 302 303 public Builder assignees(@Nullable Collection<String> l) { 304 this.assignees = l; 305 return this; 306 } 307 308 public Builder languages(@Nullable Collection<String> l) { 309 this.languages = l; 310 return this; 311 } 312 313 /** 314 * If true, it will return all issues assigned to someone 315 * If false, it will return all issues not assigned to someone 316 */ 317 public Builder assigned(@Nullable Boolean b) { 318 this.assigned = b; 319 return this; 320 } 321 322 /** 323 * If true, it will return all issues linked to an action plan 324 * If false, it will return all issues not linked to an action plan 325 */ 326 public Builder planned(@Nullable Boolean planned) { 327 this.planned = planned; 328 return this; 329 } 330 331 /** 332 * If true, it will return all resolved issues 333 * If false, it will return all none resolved issues 334 */ 335 public Builder resolved(@Nullable Boolean resolved) { 336 this.resolved = resolved; 337 return this; 338 } 339 340 /** 341 * If true, rules will not be loaded 342 * If false, rules will be loaded 343 * 344 * @since 4.2 345 * 346 */ 347 public Builder hideRules(@Nullable Boolean b) { 348 this.hideRules = b; 349 return this; 350 } 351 352 public Builder createdAt(@Nullable Date d) { 353 this.createdAt = d == null ? null : new Date(d.getTime()); 354 return this; 355 } 356 357 public Builder createdAfter(@Nullable Date d) { 358 this.createdAfter = d == null ? null : new Date(d.getTime()); 359 return this; 360 } 361 362 public Builder createdBefore(@Nullable Date d) { 363 this.createdBefore = d == null ? null : new Date(d.getTime()); 364 return this; 365 } 366 367 public Builder sort(@Nullable String s) { 368 if (s != null && !SORTS.contains(s)) { 369 throw new IllegalArgumentException("Bad sort field: " + s); 370 } 371 this.sort = s; 372 return this; 373 } 374 375 public Builder asc(@Nullable Boolean asc) { 376 this.asc = asc; 377 return this; 378 } 379 380 public Builder pageSize(@Nullable Integer i) { 381 this.pageSize = i; 382 return this; 383 } 384 385 public Builder pageIndex(@Nullable Integer i) { 386 this.pageIndex = i; 387 return this; 388 } 389 390 public Builder requiredRole(@Nullable String s) { 391 this.requiredRole = s; 392 return this; 393 } 394 395 public IssueQuery build() { 396 initPageIndex(); 397 initPageSize(); 398 if (issueKeys != null) { 399 Preconditions.checkArgument(issueKeys.size() <= MAX_PAGE_SIZE, "Number of issue keys must be less than " + MAX_PAGE_SIZE + " (got " + issueKeys.size() + ")"); 400 } 401 return new IssueQuery(this); 402 } 403 404 private void initPageSize() { 405 if (components != null && components.size() == 1 && pageSize == null) { 406 pageSize = 999999; 407 } else { 408 if (pageSize == null) { 409 pageSize = DEFAULT_PAGE_SIZE; 410 } else if (pageSize <= 0 || pageSize > MAX_PAGE_SIZE) { 411 pageSize = MAX_PAGE_SIZE; 412 } 413 } 414 } 415 416 private void initPageIndex() { 417 if (pageIndex == null) { 418 pageIndex = DEFAULT_PAGE_INDEX; 419 } 420 Preconditions.checkArgument(pageIndex > 0, "Page index must be greater than 0 (got " + pageIndex + ")"); 421 } 422 } 423 424 private static <T> Collection<T> defaultCollection(@Nullable Collection<T> c) { 425 return c == null ? Collections.<T>emptyList() : Collections.unmodifiableCollection(c); 426 } 427 }