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