Skip to content

Commit

Permalink
Merge pull request #1920 from Shyri/android-volley-library
Browse files Browse the repository at this point in the history
Android volley library enhancement and tests
  • Loading branch information
wing328 committed Jan 22, 2016
2 parents 53abd8a + 877661a commit 03b463b
Show file tree
Hide file tree
Showing 6 changed files with 598 additions and 30 deletions.
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

0 comments on commit 03b463b

Please sign in to comment.