001/* 002 * SonarQube 003 * Copyright (C) 2009-2016 SonarSource SA 004 * mailto:contact AT sonarsource DOT com 005 * 006 * This program 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 * This program 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.server.ws; 021 022import com.google.common.annotations.Beta; 023import com.google.common.base.Splitter; 024import com.google.common.collect.Lists; 025import java.io.InputStream; 026import java.util.ArrayList; 027import java.util.Date; 028import java.util.List; 029import javax.annotation.CheckForNull; 030import org.apache.commons.lang.StringUtils; 031import org.sonar.api.utils.DateUtils; 032import org.sonar.api.utils.SonarException; 033 034import static com.google.common.base.Preconditions.checkArgument; 035import static org.sonar.api.utils.DateUtils.parseDateQuietly; 036import static org.sonar.api.utils.DateUtils.parseDateTimeQuietly; 037 038/** 039 * @since 4.2 040 */ 041public abstract class Request { 042 043 private static final String MSG_PARAMETER_MISSING = "The '%s' parameter is missing"; 044 045 /** 046 * Returns the name of the HTTP method with which this request was made. Possible 047 * values are GET and POST. Others are not supported. 048 */ 049 public abstract String method(); 050 051 /** 052 * Returns the requested MIME type, or {@code "application/octet-stream"} if not specified. 053 */ 054 public abstract String getMediaType(); 055 056 /** 057 * Return true of the parameter is set. 058 */ 059 public abstract boolean hasParam(String key); 060 061 /** 062 * Returns a non-null value. To be used when parameter is required or has a default value. 063 * 064 * @throws java.lang.IllegalArgumentException is value is null or blank 065 */ 066 public String mandatoryParam(String key) { 067 String value = param(key); 068 if (value == null) { 069 throw new IllegalArgumentException(String.format(MSG_PARAMETER_MISSING, key)); 070 } 071 return value; 072 } 073 074 /** 075 * Returns a boolean value. To be used when parameter is required or has a default value. 076 * 077 * @throws java.lang.IllegalArgumentException is value is null or blank 078 */ 079 public boolean mandatoryParamAsBoolean(String key) { 080 String s = mandatoryParam(key); 081 return parseBoolean(key, s); 082 } 083 084 /** 085 * Returns an int value. To be used when parameter is required or has a default value. 086 * 087 * @throws java.lang.IllegalArgumentException is value is null or blank 088 */ 089 public int mandatoryParamAsInt(String key) { 090 String s = mandatoryParam(key); 091 return parseInt(key, s); 092 } 093 094 /** 095 * Returns a long value. To be used when parameter is required or has a default value. 096 * 097 * @throws java.lang.IllegalArgumentException is value is null or blank 098 */ 099 public long mandatoryParamAsLong(String key) { 100 String s = mandatoryParam(key); 101 return parseLong(key, s); 102 } 103 104 public <E extends Enum<E>> E mandatoryParamAsEnum(String key, Class<E> enumClass) { 105 return Enum.valueOf(enumClass, mandatoryParam(key)); 106 } 107 108 public List<String> mandatoryParamAsStrings(String key) { 109 List<String> values = paramAsStrings(key); 110 if (values == null) { 111 throw new IllegalArgumentException(String.format(MSG_PARAMETER_MISSING, key)); 112 } 113 return values; 114 } 115 116 public List<String> mandatoryMultiParam(String key) { 117 List<String> values = multiParam(key); 118 checkArgument(!values.isEmpty(), MSG_PARAMETER_MISSING, key); 119 120 return values; 121 } 122 123 @CheckForNull 124 public List<String> paramAsStrings(String key) { 125 String value = param(key); 126 if (value == null) { 127 return null; 128 } 129 return Lists.newArrayList(Splitter.on(',').omitEmptyStrings().trimResults().split(value)); 130 } 131 132 @CheckForNull 133 public abstract String param(String key); 134 135 public abstract List<String> multiParam(String key); 136 137 @CheckForNull 138 public abstract InputStream paramAsInputStream(String key); 139 140 @CheckForNull 141 public abstract Part paramAsPart(String key); 142 143 public Part mandatoryParamAsPart(String key) { 144 Part part = paramAsPart(key); 145 checkArgument(part != null, MSG_PARAMETER_MISSING, key); 146 return part; 147 } 148 149 /** 150 * @deprecated to be dropped in 4.4. Default values are declared in ws metadata 151 */ 152 @CheckForNull 153 @Deprecated 154 public String param(String key, @CheckForNull String defaultValue) { 155 return StringUtils.defaultString(param(key), defaultValue); 156 } 157 158 /** 159 * @deprecated to be dropped in 4.4. Default values must be declared in {@link org.sonar.api.server.ws.WebService} then 160 * this method can be replaced by {@link #mandatoryParamAsBoolean(String)}. 161 */ 162 @Deprecated 163 public boolean paramAsBoolean(String key, boolean defaultValue) { 164 String value = param(key); 165 return value == null ? defaultValue : parseBoolean(key, value); 166 } 167 168 /** 169 * @deprecated to be dropped in 4.4. Default values must be declared in {@link org.sonar.api.server.ws.WebService} then 170 * this method can be replaced by {@link #mandatoryParamAsInt(String)}. 171 */ 172 @Deprecated 173 public int paramAsInt(String key, int defaultValue) { 174 String s = param(key); 175 return s == null ? defaultValue : parseInt(key, s); 176 } 177 178 /** 179 * @deprecated to be dropped in 4.4. Default values must be declared in {@link org.sonar.api.server.ws.WebService} then 180 * this method can be replaced by {@link #mandatoryParamAsLong(String)}. 181 */ 182 @Deprecated 183 public long paramAsLong(String key, long defaultValue) { 184 String s = param(key); 185 return s == null ? defaultValue : parseLong(key, s); 186 } 187 188 @CheckForNull 189 public Boolean paramAsBoolean(String key) { 190 String value = param(key); 191 return value == null ? null : parseBoolean(key, value); 192 } 193 194 @CheckForNull 195 public Integer paramAsInt(String key) { 196 String s = param(key); 197 return s == null ? null : parseInt(key, s); 198 } 199 200 @CheckForNull 201 public Long paramAsLong(String key) { 202 String s = param(key); 203 return s == null ? null : parseLong(key, s); 204 } 205 206 @CheckForNull 207 public <E extends Enum<E>> E paramAsEnum(String key, Class<E> enumClass) { 208 String s = param(key); 209 return s == null ? null : Enum.valueOf(enumClass, s); 210 } 211 212 @CheckForNull 213 public <E extends Enum<E>> List<E> paramAsEnums(String key, Class<E> enumClass) { 214 String value = param(key); 215 if (value == null) { 216 return null; 217 } 218 Iterable<String> values = Splitter.on(',').omitEmptyStrings().trimResults().split(value); 219 List<E> result = new ArrayList<>(); 220 for (String s : values) { 221 result.add(Enum.valueOf(enumClass, s)); 222 } 223 224 return result; 225 } 226 227 @CheckForNull 228 public Date paramAsDateTime(String key) { 229 String stringDate = param(key); 230 if (stringDate == null) { 231 return null; 232 } 233 234 Date date = parseDateTimeQuietly(stringDate); 235 if (date != null) { 236 return date; 237 } 238 239 date = parseDateQuietly(stringDate); 240 checkArgument(date != null, "'%s' cannot be parsed as either a date or date+time", stringDate); 241 242 return date; 243 } 244 245 @CheckForNull 246 public Date paramAsDate(String key) { 247 String s = param(key); 248 if (s == null) { 249 return null; 250 } 251 252 try { 253 return DateUtils.parseDate(s); 254 } catch (SonarException notDateException) { 255 throw new IllegalArgumentException(notDateException); 256 } 257 } 258 259 private static boolean parseBoolean(String key, String value) { 260 if ("true".equals(value) || "yes".equals(value)) { 261 return true; 262 } 263 if ("false".equals(value) || "no".equals(value)) { 264 return false; 265 } 266 throw new IllegalArgumentException(String.format("Property %s is not a boolean value: %s", key, value)); 267 } 268 269 private static int parseInt(String key, String value) { 270 try { 271 return Integer.parseInt(value); 272 } catch (NumberFormatException expection) { 273 throw new IllegalArgumentException(String.format("The '%s' parameter cannot be parsed as an integer value: %s", key, value)); 274 } 275 } 276 277 private static long parseLong(String key, String value) { 278 try { 279 return Long.parseLong(value); 280 } catch (NumberFormatException expection) { 281 throw new IllegalArgumentException(String.format("The '%s' parameter cannot be parsed as a long value: %s", key, value)); 282 } 283 } 284 285 /** 286 * Allows a web service to call another web service. 287 * @see LocalConnector 288 * @since 5.5 289 */ 290 @Beta 291 public abstract LocalConnector localConnector(); 292 293 /** 294 * Return path of the request 295 * @since 6.0 296 */ 297 public abstract String getPath(); 298 299 /** 300 * @since 6.0 301 */ 302 public interface Part { 303 InputStream getInputStream(); 304 305 String getFileName(); 306 } 307}