Skip to content

Android volley library enhancement and tests #1920

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jan 22, 2016
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ import com.android.volley.VolleyError;
import org.apache.http.HttpEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;

import java.util.Map;
import java.util.ArrayList;
import java.util.HashMap;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

{{#operations}}
public class {{classname}} {
Expand All @@ -44,11 +47,93 @@ public class {{classname}} {

{{#operation}}
/**
* {{summary}}
* {{notes}}
* {{summary}}
* {{notes}}
{{#allParams}} * @param {{paramName}} {{description}}
{{/allParams}} * @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}
*/
*/
public {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} {{nickname}} ({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws TimeoutException, ExecutionException, InterruptedException, ApiException {
Object postBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}};
{{#allParams}}{{#required}}
// verify the required parameter '{{paramName}}' is set
if ({{paramName}} == null) {
VolleyError error = new VolleyError("Missing the required parameter '{{paramName}}' when calling {{nickname}}",
new ApiException(400, "Missing the required parameter '{{paramName}}' when calling {{nickname}}"));
}
{{/required}}{{/allParams}}

// create path and map variables
String path = "{{path}}".replaceAll("\\{format\\}","json"){{#pathParams}}.replaceAll("\\{" + "{{baseName}}" + "\\}", apiInvoker.escapeString({{{paramName}}}.toString())){{/pathParams}};

// query params
List<Pair> queryParams = new ArrayList<Pair>();
// header params
Map<String, String> headerParams = new HashMap<String, String>();
// form params
Map<String, String> formParams = new HashMap<String, String>();

{{#queryParams}}
queryParams.addAll(ApiInvoker.parameterToPairs("{{#collectionFormat}}{{{collectionFormat}}}{{/collectionFormat}}", "{{baseName}}", {{paramName}}));
{{/queryParams}}

{{#headerParams}}
headerParams.put("{{baseName}}", ApiInvoker.parameterToString({{paramName}}));
{{/headerParams}}

String[] contentTypes = {
{{#consumes}}"{{mediaType}}"{{#hasMore}},{{/hasMore}}{{/consumes}}
};
String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json";

if (contentType.startsWith("multipart/form-data")) {
// file uploading
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
{{#formParams}}{{#notFile}}
if ({{paramName}} != null) {
builder.addTextBody("{{baseName}}", ApiInvoker.parameterToString({{paramName}}), ApiInvoker.TEXT_PLAIN_UTF8);
}
{{/notFile}}{{#isFile}}
if ({{paramName}} != null) {
builder.addBinaryBody("{{baseName}}", {{paramName}});
}
{{/isFile}}{{/formParams}}

HttpEntity httpEntity = builder.build();
postBody = httpEntity;
} else {
// normal form params
{{#formParams}}{{#notFile}}formParams.put("{{baseName}}", ApiInvoker.parameterToString({{paramName}}));{{/notFile}}
{{/formParams}}
}

String[] authNames = new String[] { {{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}} };

try {
String response = apiInvoker.invokeAPI (basePath, path, "{{httpMethod}}", queryParams, postBody, headerParams, formParams, contentType, authNames);
if(response != null){
return {{#returnType}}({{{returnType}}}) ApiInvoker.deserialize(response, "{{returnContainer}}", {{returnBaseType}}.class){{/returnType}};
} else {
return {{#returnType}}null{{/returnType}};
}
} catch (ApiException ex) {
throw ex;
} catch (InterruptedException ex) {
throw ex;
} catch (ExecutionException ex) {
if(ex.getCause() instanceof VolleyError) {
throw new ApiException(((VolleyError) ex.getCause()).networkResponse.statusCode, ((VolleyError) ex.getCause()).getMessage());
}
throw ex;
} catch (TimeoutException ex) {
throw ex;
}
}

/**
* {{summary}}
* {{notes}}
{{#allParams}} * @param {{paramName}} {{description}}{{/allParams}}
*/
public void {{nickname}} ({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{^hasMore}}, {{/hasMore}}{{/allParams}}final Response.Listener<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}String{{/returnType}}> responseListener, final Response.ErrorListener errorListener) {
Object postBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package {{invokerPackage}};

import android.content.Context;

import com.android.volley.Cache;
import com.android.volley.Network;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.toolbox.Volley;
import com.android.volley.ResponseDelivery;
import com.android.volley.toolbox.BasicNetwork;
import com.android.volley.toolbox.HttpStack;
import com.android.volley.toolbox.HurlStack;
import com.android.volley.toolbox.NoCache;
import com.android.volley.toolbox.RequestFuture;
import com.google.gson.JsonParseException;

import org.apache.http.Consts;
Expand All @@ -22,6 +28,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import {{invokerPackage}}.auth.Authentication;
import {{invokerPackage}}.auth.ApiKeyAuth;
Expand All @@ -36,11 +45,12 @@ public class ApiInvoker {
private static ApiInvoker INSTANCE;
private Map<String, String> defaultHeaderMap = new HashMap<String, String>();

private Context context;
private RequestQueue mRequestQueue;

private Map<String, Authentication> authentications;

private int connectionTimeout;

/** Content type "text/plain" with UTF-8 encoding. */
public static final ContentType TEXT_PLAIN_UTF8 = ContentType.create("text/plain", Consts.UTF_8);

Expand Down Expand Up @@ -165,8 +175,16 @@ public class ApiInvoker {
return params;
}

public static void initializeInstance(Context context) {
INSTANCE = new ApiInvoker(context);
public static void initializeInstance() {
initializeInstance(null);
}

public static void initializeInstance(Cache cache) {
initializeInstance(cache, null, 0, null, 30);
}

public static void initializeInstance(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery, int connectionTimeout) {
INSTANCE = new ApiInvoker(cache, network, threadPoolSize, delivery, connectionTimeout);
setUserAgent("Android-Volley-Swagger");

// Setup authentications (key: authentication name, value: authentication).
Expand All @@ -178,17 +196,27 @@ public class ApiInvoker {
{{#isBasic}}
INSTANCE.authentications.put("{{name}}", new HttpBasicAuth());
{{/isBasic}}
{{#isOAuth}}
INSTANCE.authentications.put("{{name}}", new OAuth());
{{/isOAuth}}
{{/authMethods}}
// Prevent the authentications from being modified.
INSTANCE.authentications = Collections.unmodifiableMap(INSTANCE.authentications);
}
private ApiInvoker(Context context) {
this.context = context;
initConnectionManager();
}

public ApiInvoker() {
initConnectionManager();
private ApiInvoker(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery, int connectionTimeout) {
if(cache == null) cache = new NoCache();
if(network == null) {
HttpStack stack = new HurlStack();
network = new BasicNetwork(stack);
}

if(delivery == null) {
initConnectionRequest(cache, network);
} else {
initConnectionRequest(cache, network, threadPoolSize, delivery);
}
this.connectionTimeout = connectionTimeout;
}

public static ApiInvoker getInstance() {
Expand Down Expand Up @@ -304,6 +332,14 @@ public class ApiInvoker {
throw new RuntimeException("No API key authentication configured!");
}

public void setConnectionTimeout(int connectionTimeout){
this.connectionTimeout = connectionTimeout;
}

public int getConnectionTimeout() {
return connectionTimeout;
}

/**
* Update query and header parameters based on authentication settings.
*
Expand All @@ -317,7 +353,21 @@ public class ApiInvoker {
}
}

public String invokeAPI(String host, String path, String method, List<Pair> queryParams, Object body, Map<String, String> headerParams, Map<String, String> formParams, String contentType, String[] authNames) throws ApiException, InterruptedException, ExecutionException, TimeoutException {
RequestFuture<String> future = RequestFuture.newFuture();
Request request = createRequest(host, path, method, queryParams, body, headerParams, formParams, contentType, authNames, future, future);
if(request != null) {
mRequestQueue.add(request);
return future.get(connectionTimeout, TimeUnit.SECONDS);
} else return "no data";
}

public void invokeAPI(String host, String path, String method, List<Pair> queryParams, Object body, Map<String, String> headerParams, Map<String, String> formParams, String contentType, String[] authNames, Response.Listener<String> stringRequest, Response.ErrorListener errorListener) throws ApiException {
Request request = createRequest(host, path, method, queryParams, body, headerParams, formParams, contentType, authNames, stringRequest, errorListener);
if (request != null) mRequestQueue.add(request);
}

public Request<String> createRequest(String host, String path, String method, List<Pair> queryParams, Object body, Map<String, String> headerParams, Map<String, String> formParams, String contentType, String[] authNames, Response.Listener<String> stringRequest, Response.ErrorListener errorListener) throws ApiException {
StringBuilder b = new StringBuilder();
b.append("?");

Expand Down Expand Up @@ -374,13 +424,13 @@ public class ApiInvoker {
}
formParamStr = formParamBuilder.toString();
}
Request request = null;

if ("GET".equals(method)) {
GetRequest request = new GetRequest(url, headers, null, stringRequest, errorListener);
mRequestQueue.add(request);
request = new GetRequest(url, headers, null, stringRequest, errorListener);
}
else if ("POST".equals(method)) {
PostRequest request = null;
request = null;
if (formParamStr != null) {
request = new PostRequest(url, headers, contentType, new StringEntity(formParamStr, "UTF-8"), stringRequest, errorListener);
} else if (body != null) {
Expand All @@ -389,11 +439,12 @@ public class ApiInvoker {
} else {
request = new PostRequest(url, headers, contentType, new StringEntity(serialize(body), "UTF-8"), stringRequest, errorListener);
}
} else {
request = new PostRequest(url, headers, null, null, stringRequest, errorListener);
}
if(request != null) mRequestQueue.add(request);
}
else if ("PUT".equals(method)) {
PutRequest request = null;
request = null;
if (formParamStr != null) {
request = new PutRequest(url, headers, contentType, new StringEntity(formParamStr, "UTF-8"), stringRequest, errorListener);
} else if (body != null) {
Expand All @@ -402,11 +453,12 @@ public class ApiInvoker {
} else {
request = new PutRequest(url, headers, contentType, new StringEntity(serialize(body), "UTF-8"), stringRequest, errorListener);
}
} else {
request = new PutRequest(url, headers, null, null, stringRequest, errorListener);
}
if(request != null) mRequestQueue.add(request);
}
else if ("DELETE".equals(method)) {
DeleteRequest request = null;
request = null;
if (formParamStr != null) {
request = new DeleteRequest(url, headers, contentType, new StringEntity(formParamStr, "UTF-8"), stringRequest, errorListener);
} else if (body != null) {
Expand All @@ -415,11 +467,12 @@ public class ApiInvoker {
} else {
request = new DeleteRequest(url, headers, contentType, new StringEntity(serialize(body), "UTF-8"), stringRequest, errorListener);
}
} else {
request = new DeleteRequest(url, headers, null, null, stringRequest, errorListener);
}
if(request != null) mRequestQueue.add(request);
}
else if ("PATCH".equals(method)) {
PatchRequest request = null;
request = null;
if (formParamStr != null) {
request = new PatchRequest(url, headers, contentType, new StringEntity(formParamStr, "UTF-8"), stringRequest, errorListener);
} else if (body != null) {
Expand All @@ -428,12 +481,24 @@ public class ApiInvoker {
} else {
request = new PatchRequest(url, headers, contentType, new StringEntity(serialize(body), "UTF-8"), stringRequest, errorListener);
}
}
if(request != null) mRequestQueue.add(request);
} else {
request = new PatchRequest(url, headers, null, null, stringRequest, errorListener);
}
}
return request;
}

private void initConnectionRequest(Cache cache, Network network) {
mRequestQueue = new RequestQueue(cache, network);
mRequestQueue.start();
}

private void initConnectionRequest(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {
mRequestQueue = new RequestQueue(cache, network, threadPoolSize, delivery);
mRequestQueue.start();
}

private void initConnectionManager() {
mRequestQueue = Volley.newRequestQueue(context);
public void stopQueue() {
mRequestQueue.stop();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public class ApiKeyAuth implements Authentication {
@Override
public void applyToParams(List<Pair> queryParams, Map<String, String> headerParams) {
String value;
if (apiKey == null) {
return;
}
if (apiKeyPrefix != null) {
value = apiKeyPrefix + " " + apiKey;
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package {{invokerPackage}}.auth;

import {{invokerPackage}}.Pair;

import java.util.Map;
import java.util.List;

public class OAuth implements Authentication {
@Override
public void applyToParams(List<Pair> queryParams, Map<String, String> headerParams) {
// TODO stub
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ android {
}
}
}

testOptions {
unitTests.returnDefaultValues = true
}
}


Expand All @@ -58,6 +62,8 @@ ext {
httpclient_version = "4.3.3"
volley_version = "1.0.19"
junit_version = "4.8.1"
robolectric_version = "3.0"
concurrent_unit_version = "0.4.2"
}

dependencies {
Expand All @@ -67,6 +73,8 @@ dependencies {
compile "org.apache.httpcomponents:httpmime:$httpclient_version"
compile "com.mcxiaoke.volley:library:${volley_version}@aar"
testCompile "junit:junit:$junit_version"
testCompile "org.robolectric:robolectric:${robolectric_version}"
testCompile "net.jodah:concurrentunit:${concurrentunitVersion}"
}

afterEvaluate {
Expand Down
Loading