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.internal; 021 022import com.google.common.base.CharMatcher; 023import com.google.common.base.Splitter; 024import com.google.common.collect.Lists; 025import java.io.InputStream; 026import java.util.ArrayList; 027import java.util.List; 028import java.util.Set; 029import javax.annotation.CheckForNull; 030import javax.annotation.Nullable; 031import org.apache.commons.lang.StringUtils; 032import org.sonar.api.server.ws.LocalConnector; 033import org.sonar.api.server.ws.Request; 034import org.sonar.api.server.ws.WebService; 035 036import static com.google.common.base.Preconditions.checkArgument; 037import static com.google.common.base.Preconditions.checkNotNull; 038import static java.util.Collections.emptyList; 039import static java.util.Collections.singletonList; 040 041/** 042 * @since 4.2 043 */ 044public abstract class ValidatingRequest extends Request { 045 046 private WebService.Action action; 047 private LocalConnector localConnector; 048 049 public void setAction(WebService.Action action) { 050 this.action = action; 051 } 052 053 public WebService.Action action() { 054 return action; 055 } 056 057 @Override 058 public LocalConnector localConnector() { 059 checkNotNull(localConnector, "Local connector has not been set"); 060 return localConnector; 061 } 062 063 public void setLocalConnector(LocalConnector lc) { 064 this.localConnector = lc; 065 } 066 067 @Override 068 @CheckForNull 069 public String param(String key) { 070 return param(key, true); 071 } 072 073 @Override 074 public List<String> multiParam(String key) { 075 WebService.Param definition = action.param(key); 076 List<String> values = readMultiParamOrDefaultValue(key, definition); 077 078 values.forEach(value -> validate(value, definition)); 079 080 return values; 081 } 082 083 @Override 084 @CheckForNull 085 public InputStream paramAsInputStream(String key) { 086 return readInputStreamParam(key); 087 } 088 089 @Override 090 @CheckForNull 091 public Part paramAsPart(String key) { 092 return readPart(key); 093 } 094 095 @CheckForNull 096 private String param(String key, boolean validateValue) { 097 WebService.Param definition = action.param(key); 098 String value = readParamOrDefaultValue(key, definition); 099 String trimmedValue = value == null ? value : CharMatcher.WHITESPACE.trimFrom(value); 100 if (trimmedValue != null && validateValue) { 101 validate(trimmedValue, definition); 102 } 103 return trimmedValue; 104 } 105 106 @CheckForNull 107 @Override 108 public List<String> paramAsStrings(String key) { 109 WebService.Param definition = action.param(key); 110 String value = readParamOrDefaultValue(key, definition); 111 if (value == null) { 112 return null; 113 } 114 List<String> values = Lists.newArrayList(Splitter.on(',').omitEmptyStrings().trimResults().split(value)); 115 for (String s : values) { 116 validate(s, definition); 117 } 118 return values; 119 } 120 121 @CheckForNull 122 @Override 123 public <E extends Enum<E>> List<E> paramAsEnums(String key, Class<E> enumClass) { 124 WebService.Param definition = action.param(key); 125 String value = readParamOrDefaultValue(key, definition); 126 if (value == null) { 127 return null; 128 } 129 Iterable<String> values = Splitter.on(',').omitEmptyStrings().trimResults().split(value); 130 List<E> result = new ArrayList<>(); 131 for (String s : values) { 132 validate(s, definition); 133 result.add(Enum.valueOf(enumClass, s)); 134 } 135 return result; 136 } 137 138 @CheckForNull 139 private String readParamOrDefaultValue(String key, @Nullable WebService.Param definition) { 140 checkArgument(definition != null, "BUG - parameter '%s' is undefined for action '%s'", key, action.key()); 141 142 String deprecatedKey = definition.deprecatedKey(); 143 String value = deprecatedKey != null ? StringUtils.defaultString(readParam(deprecatedKey), readParam(key)) : readParam(key); 144 value = StringUtils.defaultString(value, definition.defaultValue()); 145 return value == null ? null : value; 146 } 147 148 private List<String> readMultiParamOrDefaultValue(String key, @Nullable WebService.Param definition) { 149 checkArgument(definition != null, "BUG - parameter '%s' is undefined for action '%s'", key, action.key()); 150 151 List<String> keyValues = readMultiParam(key); 152 if (!keyValues.isEmpty()) { 153 return keyValues; 154 } 155 156 String deprecatedKey = definition.deprecatedKey(); 157 List<String> deprecatedKeyValues = deprecatedKey == null ? emptyList() : readMultiParam(deprecatedKey); 158 if (!deprecatedKeyValues.isEmpty()) { 159 return deprecatedKeyValues; 160 } 161 162 String defaultValue = definition.defaultValue(); 163 return defaultValue == null ? emptyList() : singletonList(defaultValue); 164 } 165 166 @CheckForNull 167 protected abstract String readParam(String key); 168 169 protected abstract List<String> readMultiParam(String key); 170 171 @CheckForNull 172 protected abstract InputStream readInputStreamParam(String key); 173 174 @CheckForNull 175 protected abstract Part readPart(String key); 176 177 private static void validate(String value, WebService.Param definition) { 178 Set<String> possibleValues = definition.possibleValues(); 179 if (possibleValues != null && !possibleValues.contains(value)) { 180 throw new IllegalArgumentException(String.format( 181 "Value of parameter '%s' (%s) must be one of: %s", definition.key(), value, possibleValues)); 182 } 183 } 184}