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