/** * Copyright 2014 Opower, Inc. * 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. **/ package com.opower.rest.client.generator.core; import com.google.common.base.Predicate; import com.opower.rest.client.generator.specimpl.MultivaluedMapImpl; import com.opower.rest.client.generator.specimpl.UriBuilderImpl; import com.opower.rest.client.generator.util.Encode; import com.opower.rest.client.generator.util.HttpHeaderNames; import com.opower.rest.client.generator.util.StringConverter; import com.opower.rest.client.generator.util.StringConverters; import javax.ws.rs.core.Cookie; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Providers; import java.io.IOException; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.List; import java.util.Map; /** * Create a hand coded request to send to the server. You call methods like accept(), body(), pathParameter() * etc. to create the state of the request. Then you call a get(), post(), etc. method to execute the request. * After an execution of a request, the internal state remains the same. You can invoke the request again. * You can clear the request with the clear() method. * * @author <a href="mailto:sduskis@gmail.com">Solomon Duskis</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:sachin.nene@opower.com">Sachin Nene</a> * */ @SuppressWarnings("unchecked") public class ClientRequest implements Cloneable { private final ProxyConfig proxyConfig; private final Method method; protected UriBuilderImpl uri; protected ClientExecutor executor; protected MultivaluedMap<String, Object> headers; protected MultivaluedMap<String, String> queryParameters; protected MultivaluedMap<String, String> formParameters; protected MultivaluedMap<String, String> pathParameters; protected MultivaluedMap<String, String> matrixParameters; protected Object body; protected Class bodyType; protected Type bodyGenericType; protected Annotation[] bodyAnnotations; protected MediaType bodyContentType; protected boolean followRedirects; protected String httpMethod; protected String finalUri; protected List<String> pathParameterList; public ClientRequest(String uriTemplate, ClientExecutor executor, ProxyConfig proxyConfig, Method method) { this((UriBuilderImpl) new UriBuilderImpl().uriTemplate(uriTemplate), executor, proxyConfig, method); } public ClientRequest(UriBuilderImpl uriBuilder, ClientExecutor executor, ProxyConfig proxyConfig, Method method) { this.uri = uriBuilder; this.executor = executor; this.proxyConfig = proxyConfig; this.method = method; } public boolean followRedirects() { return followRedirects; } public ClientRequest followRedirects(boolean followRedirects) { this.followRedirects = followRedirects; return this; } public ClientRequest accept(MediaType accepts) { return header(HttpHeaderNames.ACCEPT, accepts.toString()); } public ClientRequest accept(String accept) { String curr = (String) getHeadersAsObjects().getFirst(HttpHeaderNames.ACCEPT); if (curr != null) curr += "," + accept; else curr = accept; getHeadersAsObjects().putSingle(HttpHeaderNames.ACCEPT, curr); return this; } protected String toString(Object object) { if (object instanceof String) return (String) object; StringConverter converter = StringConverters.getStringConverter(object .getClass()); if (converter != null) return converter.toString(object); else return object.toString(); } protected String toHeaderString(Object object) { StringConverter converter = StringConverters.getStringConverter(object .getClass()); if (converter != null) return converter.toString(object); else return object.toString(); } public ClientRequest formParameter(String parameterName, Object value) { String stringValue = toString(value); if (stringValue != null) { getFormParameters().add(parameterName, toString(value)); } return this; } public ClientRequest queryParameter(String parameterName, Object value) { String stringValue = toString(value); if (stringValue != null) { getQueryParameters().add(parameterName, stringValue); } return this; } public ClientRequest matrixParameter(String parameterName, Object value) { String stringValue = toString(value); if (stringValue != null) { getMatrixParameters().add(parameterName, toString(value)); } return this; } public ClientRequest header(String headerName, Object value) { getHeadersAsObjects().add(headerName, value); return this; } public ClientRequest cookie(String cookieName, Object value) { return cookie(new Cookie(cookieName, toString(value))); } public ClientRequest cookie(Cookie cookie) { return header(HttpHeaders.COOKIE, cookie); } public ClientRequest pathParameter(String parameterName, Object value) { getPathParameters().add(parameterName, toString(value)); return this; } public ClientRequest body(MediaType contentType, Object data, Class type, Type genericType, Annotation[] annotations) { this.body = data; this.bodyContentType = contentType; this.bodyGenericType = genericType; this.bodyType = type; this.bodyAnnotations = annotations; return this; } public Providers getProviders() { return this.proxyConfig.getProviders(); } /** * @return a copy of all header objects converted to a string */ public MultivaluedMap<String, String> getHeaders() { MultivaluedMap<String, String> rtn = new MultivaluedMapImpl<String, String>(); if (headers == null) return rtn; for (Map.Entry<String, List<Object>> entry : headers.entrySet()) { for (Object obj : entry.getValue()) { rtn.add(entry.getKey(), toHeaderString(obj)); } } return rtn; } public MultivaluedMap<String, Object> getHeadersAsObjects() { if (headers == null) headers = new MultivaluedMapImpl<>(); return headers; } public MultivaluedMap<String, String> getQueryParameters() { if (queryParameters == null) queryParameters = new MultivaluedMapImpl<>(); return queryParameters; } public MultivaluedMap<String, String> getFormParameters() { if (formParameters == null) formParameters = new MultivaluedMapImpl<>(); return formParameters; } public MultivaluedMap<String, String> getPathParameters() { if (pathParameters == null) pathParameters = new MultivaluedMapImpl<>(); return pathParameters; } public MultivaluedMap<String, String> getMatrixParameters() { if (matrixParameters == null) matrixParameters = new MultivaluedMapImpl<>(); return matrixParameters; } public Object getBody() { return body; } public MediaType getBodyContentType() { return bodyContentType; } public String getHttpMethod() { return httpMethod; } public Predicate<Integer> getErrorStatusCriteria() { return this.proxyConfig.getErrorStatusCriteria().get(this.method); } public ClientResponse execute(String httpMethod) throws Exception { this.httpMethod = httpMethod; this.executor.processFilters(this); BaseClientResponse response = (BaseClientResponse) executor.execute(this); return response; } public void writeRequestBody(MultivaluedMap<String, Object> headers, OutputStream outputStream) throws IOException { if (body == null) { return; } MessageBodyWriter writer = this.proxyConfig.getProviders().getMessageBodyWriter(bodyType, bodyGenericType, bodyAnnotations, bodyContentType); if (writer == null) { throw new RuntimeException("could not find writer for content-type " + bodyContentType + " type: " + bodyType.getName()); } writer.writeTo(body, bodyType, bodyGenericType, bodyAnnotations, bodyContentType, headers, outputStream); } /** * This method populates all path, matrix, and query parameters and saves it * internally. Once its called once it returns the cached value. * * @return * @throws Exception */ public String getUri() throws Exception { if (finalUri != null) return finalUri; UriBuilderImpl builder = (UriBuilderImpl) uri.clone(); if (matrixParameters != null) { for (Map.Entry<String, List<String>> entry : matrixParameters .entrySet()) { List<String> values = entry.getValue(); for (String value : values) builder.matrixParam(entry.getKey(), value); } } if (queryParameters != null) { for (Map.Entry<String, List<String>> entry : queryParameters .entrySet()) { List<String> values = entry.getValue(); for (String value : values) builder.clientQueryParam(entry.getKey(), value); } } if (pathParameterList != null && !pathParameterList.isEmpty()) { finalUri = builder.build(pathParameterList.toArray()).toString(); } else if (pathParameters != null && !pathParameters.isEmpty()) { for (Map.Entry<String, List<String>> entry : pathParameters.entrySet()) { List<String> values = entry.getValue(); for (String value : values) { value = Encode.encodePathAsIs(value); builder.substitutePathParam(entry.getKey(), value, true); } } } if (finalUri == null) finalUri = builder.build().toString(); return finalUri; } }