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