com.lonepulse.zombielink.request.QueryParamProcessor Maven / Gradle / Ivy
package com.lonepulse.zombielink.request;
/*
* #%L
* ZombieLink
* %%
* Copyright (C) 2013 - 2014 Lonepulse
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import com.lonepulse.zombielink.annotation.Param;
import com.lonepulse.zombielink.annotation.QueryParam;
import com.lonepulse.zombielink.annotation.QueryParams;
import com.lonepulse.zombielink.proxy.InvocationContext;
import com.lonepulse.zombielink.util.Metadata;
/**
* This {@link AbstractRequestProcessor} discovers query parameters in a request which are
* annotated with @{@link QueryParam} or @{@link QueryParams} and constructs a
* query string to be appended to the URL.
*
* The @{@link QueryParam} annotation should be used on an implementation of {@link CharSequence} which
* provides the value for each name-value pair; and the supplied {@link QueryParam#value()}
* provides the name.
*
* The @{@link QueryParams} annotation should be used on a {@code Map} of
* name and value pairs.
*
* Processor Dependencies:
*
* - {@link UriProcessor}
*
*
* @version 1.3.0
*
* @since 1.3.0
*
* @author Lahiru Sahan Jayasinghe
*/
class QueryParamProcessor extends AbstractRequestProcessor {
/**
* Accepts the {@link InvocationContext} along with an {@link HttpRequestBase} and creates a
* query string using arguments annotated
* with @{@link QueryParam} and @{@link QueryParams}; which is subsequently appended to the URI.
*
* See {@link AbstractRequestProcessor#process(InvocationContext, HttpRequestBase)}.
*
* @param context
* the {@link InvocationContext} which is used to discover annotated query parameters
*
* @param request
* prefers an instance of {@link HttpGet} so as to conform with HTTP 1.1; however, other
* request types will be entertained to allow compliance with unusual endpoint definitions
*
* @return the same instance of {@link HttpRequestBase} which was given for processing query parameters
*
* @throws RequestProcessorException
* if the creation of a query string failed due to an unrecoverable errorS
*
* @since 1.3.0
*/
@Override
protected HttpRequestBase process(InvocationContext context, HttpRequestBase request) {
try {
URIBuilder uriBuilder = new URIBuilder(request.getURI());
//add static name and value pairs
List constantQueryParams = RequestUtils.findStaticQueryParams(context);
for (Param param : constantQueryParams) {
uriBuilder.setParameter(param.name(), param.value());
}
//add individual name and value pairs
List> queryParams = Metadata.onParams(QueryParam.class, context);
for (Entry entry : queryParams) {
String name = entry.getKey().value();
Object value = entry.getValue();
if(!(value instanceof CharSequence)) {
StringBuilder errorContext = new StringBuilder()
.append("Query parameters can only be of type ")
.append(CharSequence.class.getName())
.append(". Please consider implementing CharSequence ")
.append("and providing a meaningful toString() representation for the ")
.append(" of the query parameter. ");
throw new RequestProcessorException(new IllegalArgumentException(errorContext.toString()));
}
uriBuilder.setParameter(name, ((CharSequence)value).toString());
}
//add batch name and value pairs (along with any static params)
List> queryParamMaps = Metadata.onParams(QueryParams.class, context);
for (Entry entry : queryParamMaps) {
Param[] constantParams = entry.getKey().value();
if(constantParams != null && constantParams.length > 0) {
for (Param param : constantParams) {
uriBuilder.setParameter(param.name(), param.value());
}
}
Object map = entry.getValue();
if(!(map instanceof Map)) {
StringBuilder errorContext = new StringBuilder()
.append("@QueryParams can only be applied on s. ")
.append("Please refactor the method to provide a Map of name and value pairs. ");
throw new RequestProcessorException(new IllegalArgumentException(errorContext.toString()));
}
Map, ?> nameAndValues = (Map, ?>)map;
for (Entry, ?> nameAndValue : nameAndValues.entrySet()) {
Object name = nameAndValue.getKey();
Object value = nameAndValue.getValue();
if(!(name instanceof CharSequence &&
(value instanceof CharSequence || value instanceof Collection))) {
StringBuilder errorContext = new StringBuilder()
.append("The identified by @QueryParams can only contain mappings of type ")
.append(" or ")
.append(">");
throw new RequestProcessorException(new IllegalArgumentException(errorContext.toString()));
}
if(value instanceof CharSequence) {
uriBuilder.addParameter(((CharSequence)name).toString(), ((CharSequence)value).toString());
}
else { //add multi-valued query params
Collection> multivalues = (Collection>) value;
for (Object multivalue : multivalues) {
if(!(multivalue instanceof CharSequence)) {
StringBuilder errorContext = new StringBuilder()
.append("Values for the identified by @QueryParams can only contain collections ")
.append("of type java.util.Collection extends CharSequence>");
throw new RequestProcessorException(new IllegalArgumentException(errorContext.toString()));
}
uriBuilder.addParameter(((CharSequence)name).toString(), ((CharSequence)multivalue).toString());
}
}
}
}
request.setURI(uriBuilder.build());
return request;
}
catch(Exception e) {
throw (e instanceof RequestProcessorException)?
(RequestProcessorException)e :new RequestProcessorException(context, getClass(), e);
}
}
}