//
// Copyright (c) 2014 VK.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
package com.vk.sdk.api.httpClient;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import com.vk.sdk.VKSdkVersion;
import com.vk.sdk.VKUIHelper;
import com.vk.sdk.api.VKParameters;
import com.vk.sdk.api.VKRequest;
import com.vk.sdk.api.model.VKAttachments;
import com.vk.sdk.util.VKStringJoiner;
import com.vk.sdk.util.VKUtil;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* Class provides configured http client for API request loading
*/
public class VKHttpClient extends DefaultHttpClient {
private static VKHttpClient sInstance;
/**
* Default constructor from basic class
*
* @param conman The connection manager
* @param params The parameters
*/
private VKHttpClient(ClientConnectionManager conman, HttpParams params) {
super(conman, params);
}
/**
* Creates the http client (if need). Returns reusing client
*
* @return Prepared client used for API requests loading
*/
public static VKHttpClient getClient() {
if (sInstance == null) {
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http",
PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https",
SSLSocketFactory.getSocketFactory(), 443));
HttpParams params = new BasicHttpParams();
Context ctx = VKUIHelper.getApplicationContext();
try {
if (ctx != null)
{
PackageManager packageManager = ctx.getPackageManager();
if (packageManager != null) {
PackageInfo info = packageManager.getPackageInfo(ctx.getPackageName(), 0);
params.setParameter(CoreProtocolPNames.USER_AGENT,
String.format(Locale.US,
"%s/%s (%s; Android %d; Scale/%.2f; VK SDK %s; %s)",
VKUtil.getApplicationName(ctx), info.versionName,
Build.MODEL, Build.VERSION.SDK_INT,
ctx.getResources().getDisplayMetrics().density,
VKSdkVersion.SDK_VERSION,
info.packageName));
}
}
} catch (Exception ignored) {
}
sInstance = new VKHttpClient(new ThreadSafeClientConnManager(params, schemeRegistry),
params);
}
return sInstance;
}
/**
* Prepares new "normal" request from VKRequest
*
* @param vkRequest Request, created for some method
* @return Prepared request for creating VKHttpOperation
*/
public static HttpUriRequest requestWithVkRequest(VKRequest vkRequest) {
HttpUriRequest request = null;
VKParameters preparedParameters = vkRequest.getPreparedParameters();
StringBuilder urlStringBuilder = new StringBuilder(
String.format(Locale.US, "http%s://api.vk.com/method/%s",
vkRequest.secure ? "s" : "", vkRequest.methodName));
switch (vkRequest.httpMethod) {
case GET:
if (preparedParameters.size() > 0) {
urlStringBuilder.append("?").append(VKStringJoiner.joinUriParams(preparedParameters));
}
request = new HttpGet(urlStringBuilder.toString());
break;
case POST:
HttpPost post = new HttpPost(urlStringBuilder.toString());
ArrayList<NameValuePair> pairs = new ArrayList<NameValuePair>(preparedParameters.size());
for (Map.Entry<String, Object> entry : preparedParameters.entrySet()) {
Object value = entry.getValue();
if (value instanceof VKAttachments) {
pairs.add(new BasicNameValuePair(entry.getKey(), ((VKAttachments)value).toAttachmentsString()));
}
else if (value instanceof Collection) {
Collection<?> values = (Collection<?>) value;
for (Object v : values) {
// This will add a parameter for each value in the Collection/List
pairs.add(new BasicNameValuePair(String.format("%s[]", entry.getKey()), v == null ? null : String.valueOf(v)));
}
} else {
pairs.add(new BasicNameValuePair(entry.getKey(), value == null ? null : String.valueOf(value)));
}
}
try {
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(pairs, "UTF-8");
post.setEntity(entity);
} catch (UnsupportedEncodingException e) {
return null;
}
request = post;
break;
}
Map<String, String> defaultHeaders = getDefaultHeaders();
for (String key : defaultHeaders.keySet()) {
request.addHeader(key, defaultHeaders.get(key));
}
return request;
}
public static HttpPost fileUploadRequest(String uploadUrl, File... files) {
HttpPost post = new HttpPost(uploadUrl);
post.setEntity(new VKMultipartEntity(files));
return post;
}
/**
* Returns map of default headers for any request
*
* @return Map of default headers
*/
private static Map<String, String> getDefaultHeaders() {
return new HashMap<String, String>() {/**
*
*/
private static final long serialVersionUID = 200199014417610665L;
{
put("Accept-Encoding", "gzip");
}};
}
/**
* Executor for performing requests in background
*/
private static final Executor mBackgroundExecutor = Executors.newCachedThreadPool();
/**
* Starts operation in the one of network threads
*
* @param operation Operation to start
*/
public static void enqueueOperation(final VKAbstractOperation operation) {
mBackgroundExecutor.execute(new Runnable() {
@Override
public void run() {
operation.start();
}
});
}
/**
* Cancel http operation request on background thread (to prevent exception)
* @param operation executing http operation
*/
public static void cancelHttpOperation(final VKHttpOperation operation) {
mBackgroundExecutor.execute(new Runnable() {
@Override
public void run() {
operation.getUriRequest().abort();
}
});
}
}