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