All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sdklite.sphere.restful.ServiceStubInvocation Maven / Gradle / Ivy

The newest version!
package com.sdklite.sphere.restful;

import java.io.InputStream;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.HttpURLConnection;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import android.content.Context;
import android.content.pm.PackageManager;
import android.net.http.AndroidHttpClient;
import android.net.Uri;
import android.os.Build;

import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpResponse;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.util.EntityUtils;

import org.json.JSONException;
import org.json.JSONTokener;

import com.sdklite.sphere.logging.Logger;
import com.sdklite.sphere.logging.LoggerFactory;
import com.sdklite.sphere.restful.annotation.HttpDelete;
import com.sdklite.sphere.restful.annotation.HttpGet;
import com.sdklite.sphere.restful.annotation.HttpPost;
import com.sdklite.sphere.restful.annotation.HttpPut;
import com.sdklite.sphere.restful.annotation.Path;
import com.sdklite.sphere.restful.annotation.BodyParameter;
import com.sdklite.sphere.restful.annotation.MatrixParameter;
import com.sdklite.sphere.restful.annotation.PathParameter;
import com.sdklite.sphere.restful.annotation.QueryParameter;

class ServiceStubInvocation implements Invocation {

    private static final Logger logger = LoggerFactory.getLogger("ServiceStubInvocation");

    final Context context;

    final Class iface;

    final Method method;

    final String baseUrl;

    final Map headers;

    ServiceStubInvocation(final Context context, final Class iface, final Method method, final String baseUrl) {
        this(context, iface, method, baseUrl, Collections.emptyMap());
    }

    ServiceStubInvocation(final Context context, final Class iface, final Method method, final String baseUrl, final Map headers) {
        this.context = context;
        this.iface = iface;
        this.method = method;
        this.baseUrl = baseUrl;
        this.headers = null == headers ? Collections.emptyMap() : headers;
    }

    @Override
    public Object invoke(final Object... args) throws InvocationException {
        final String userAgent = this.buildUserAgent(this.context);
        final AndroidHttpClient client = AndroidHttpClient.newInstance(userAgent, this.context);

        try {
            return this.invoke(client, args);
        } finally {
            client.close();
        }
    }

    public Object invoke(final AndroidHttpClient client, final Object... args) throws InvocationException {
        logger.debug("Invoking " + this.iface.getName() + "#" + this.method.getName() + " " + Arrays.toString(args));

        if (!this.iface.isAnnotationPresent(Path.class)) {
            throw new UnsupportedOperationException(this.iface.getName() + " does not annotated by @Path");
        }

        final String httpMethod;
        final String apiPath;
        final String svcPath = this.iface.getAnnotation(Path.class).value();

        if (this.method.isAnnotationPresent(HttpPost.class)) {
            httpMethod = "POST";
            apiPath = this.method.getAnnotation(HttpPost.class).value();
        } else if (this.method.isAnnotationPresent(HttpPut.class)) {
            httpMethod = "PUT";
            apiPath = this.method.getAnnotation(HttpPut.class).value();
        } else if (this.method.isAnnotationPresent(HttpDelete.class)) {
            httpMethod = "DELETE";
            apiPath = this.method.getAnnotation(HttpDelete.class).value();
        } else if (this.method.isAnnotationPresent(HttpGet.class)) {
            httpMethod = "GET";
            apiPath = this.method.getAnnotation(HttpGet.class).value();
        } else {
            throw new UnsupportedOperationException(this.method.getName() + " does not annotated by any HTTP method");
        }

        final List bodyParams = new ArrayList();
        final List matrixParams = new ArrayList();
        final List pathParams = new ArrayList();
        final List queryParams = new ArrayList();
        final Annotation[][] paramAnnotations = method.getParameterAnnotations();
        if (null != paramAnnotations && paramAnnotations.length > 0) {
            for (int i = 0; i < paramAnnotations.length; i++) {
                final String value = String.valueOf(args[i]);
                final Annotation[] annotations = paramAnnotations[i];

                if (null != annotations && annotations.length > 0) {
                    for (final Annotation annotation : annotations) {
                        final Class annotationType = annotation.annotationType();

                        if (QueryParameter.class.equals(annotationType)) {
                            final String name = ((QueryParameter) annotation).value();
                            queryParams.add(new BasicNameValuePair(name, value));
                        } else if (BodyParameter.class.equals(annotationType)) {
                            final String name = ((BodyParameter) annotation).value();
                            bodyParams.add(new BasicNameValuePair(name, value));
                        } else if (PathParameter.class.equals(annotationType)) {
                            final String name = ((PathParameter) annotation).value();
                            pathParams.add(new BasicNameValuePair(name, value));
                        } else if (MatrixParameter.class.equals(annotationType)) {
                            final String name = ((MatrixParameter) annotation).value();
                            matrixParams.add(new BasicNameValuePair(name, value));
                        }
                    }
                }
            }
        }

        // Concatenate the query parameters with URL
        final StringBuilder queryString = new StringBuilder();
        if (queryParams.size() > 0) {
            try {
                queryString.append("?" + EntityUtils.toString(new UrlEncodedFormEntity(queryParams, "UTF-8")));
            } catch (final Exception e) {
                logger.error("Encoding query parameters error", e);
            }
        }

        // Parsing path parameters
        final String processedApiPath;
        if (pathParams.size() > 0) {
            String path = apiPath;
            for (final NameValuePair nvp : pathParams) {
                path = path.replaceAll("\\{" + nvp.getName() + "\\}", nvp.getValue());
            }
            processedApiPath = path;
        } else {
            processedApiPath = apiPath;
        }

        final HttpRequestBase request;
        final String url = baseUrl + svcPath + processedApiPath + queryString.toString();
        final InvocationTarget target = new InvocationTarget(url, httpMethod);

        logger.debug(target.toString());

        try {
            final URI uri = new URI(url);

            if (this.method.isAnnotationPresent(HttpPost.class)) {
                request = new org.apache.http.client.methods.HttpPost(uri);
            } else if (this.method.isAnnotationPresent(HttpPut.class)) {
                request = new org.apache.http.client.methods.HttpPut(uri);
            } else if (this.method.isAnnotationPresent(HttpDelete.class)) {
                request = new org.apache.http.client.methods.HttpDelete(uri);
            } else {
                request = new org.apache.http.client.methods.HttpGet(uri);
            }
        } catch (final URISyntaxException uriSyntaxException) {
            throw new InvocationException(target, null, uriSyntaxException);
        }

        HttpResponse response = null;

        try {
            request.setHeader("User-Agent", buildUserAgent(this.context));
            request.setHeader("Accept-Language", Locale.getDefault().getLanguage());

            // Set custom HTTP headers
            for (final Map.Entry entry : this.headers.entrySet()) {
                request.setHeader(entry.getKey(), entry.getValue());
            }

            // Fill request body if parameters assigned
            if (request instanceof HttpEntityEnclosingRequest) {
                final HttpEntity entity = new UrlEncodedFormEntity(bodyParams, "UTF-8");
                ((HttpEntityEnclosingRequest) request).setEntity(entity);
            }

            if (null == (response = client.execute(request))) {
                throw new InvocationException(target);
            }
        } catch (final IOException e) {
            throw new InvocationException(target);
        }

        final StatusLine status = response.getStatusLine();
        if (null == status) {
            throw new InvocationException(target, status);
        }

        switch (status.getStatusCode()) {
        case 200: {
            final HttpEntity entity = response.getEntity();
            if (null == entity) {
                throw new InvocationException(target, status);
            }

            try {
                return new JSONTokener(EntityUtils.toString(entity)).nextValue();
            } catch (final Exception e) {
                throw new InvocationException(target, status, e);
            }
        }
        default:
            logger.debug(status.toString());
            throw new InvocationException(target, status);
        }
    }

    static String buildUserAgent(final Context context) {
        final String osVersion = "Android/" + Build.VERSION.RELEASE;
        final PackageManager pm = context.getPackageManager();
        final String packageName = context.getPackageName();

        try {
            final String versionName = pm.getPackageInfo(packageName, 0).versionName;
            return osVersion + " " + packageName + "/" + versionName;
        } catch (final Exception e) {
            return osVersion;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy